-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Priority Messages #73
base: master
Are you sure you want to change the base?
Conversation
785c05e
to
6ed62ec
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty cool, I was hoping for something like this for a while ❤️
long time until the receiver fetch this message. The situation will at this | ||
point very likely have become even worse. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or the situation could have resolved itself by then (like, if the messages occur in sudden bursts in a by and large relaxed scenario), at which point it would be too late to change handling strategies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the message comes so late that it does not reflect the current state and you may not want to act on it. I'll rewrite this.
The receiver process can at any time disable reception of certain priority | ||
messages by passing `false` as second argument to any of the above listed | ||
`process_flag/2` BIF calls. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a sending process specified in a priority process flag exits, will it automatically be removed from the process flags of the receiver?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the reference implementation this is currently not done, but this can be implemented.
* *Priority Marked Messages* - A message is marked as a priority message by the | ||
sender by passing the option `priority` in the option list that is passed as | ||
third argument to the `erlang:send/3` BIF. The receiver opts-in for reception | ||
of priority marked messages from a specific sender by calling the | ||
`process_flag/2` BIF like this: | ||
`process_flag({priority_marked_message, SenderPid}, true)`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder, how could this be put to work for system
messages originating from sys
and, by extension, from proc_lib
? One would probably want to prioritize those, but AFAICT the sending process is the calling or a freshly spawned process, ie it can't be known to set the SenderPid
for the priority_marked_message
flag in the receiving process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that I think about it, this restriction to prioritize messages from a specific sender pid comes with a catch.
Contrived example:
Let's say a process A configures priority_marked_message
for messages from another process B. Process B however starts another process C to perform some complicated task (in order to stay itself responsive meanwhile), and in the end this process C should send a priority message on behalf of process B to process A. But since process C is not configured for priority_marked_message
in process A, this message (which, again, is sent on behalf of but not by process B) won't be prioritized in the mailbox of process A.
So, as a first idea, maybe priority_marked_message
should accept aliases too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder, how could this be put to work for
system
messages originating fromsys
and, by extension, fromproc_lib
?
To me it feels a bit like stretching what the priority messages was intended for
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, as a first idea, maybe
priority_marked_message
should accept aliases too?
Hmm, I like it. Perhaps the priority
option can be replaced with priority aliases all together.
multiple priority messages would accumulate in reverse order. Having these two | ||
sets of messages ordered internally by reception order at least to me feels the | ||
most useful. Just as in the case of ordinary messages we will probably want to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, keeping reception order is important, imperative, the only sensible thing to do. More so since the receiving process can't distinguish prioritized from ordinary messages.
|
||
Note that the reception order of signals is not changed. If a process sends an | ||
ordinary message and then a priority message to a another process, the ordinary | ||
message will be received first and then the priority message will be received. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"received" here doesn't mean "returned by receive
" I take it, since the whole point of this proposal is to change that order?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Certainly, but it leads to an interesting point.
If the order of events turns out like this...
- process A sends ordinary message M to process B
- process A sends prio message P to process B
- process B calls
receive
- process B calls
receive
... then process B will receive
the messages in order P
then M
.
However, if the order of events turns out like this...
- process A sends ordinary message M to process B
- process B calls
receive
- process A sends prio message P to process B
- process B calls
receive
... then process B will receive
the messages in order M
then P
.
To be clear, that is pretty much as expected. It could/should be mentioned maybe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"received" here doesn't mean "returned by
receive
" I take it, since the whole point of this proposal is to change that order?
Correct. The signal is received before it is inserted into the message queue. The name of the receive
expression is in my opinion quite misleading. A less misleading name (although not as nice name) could have been fetch_message_from_message_queue
.
The reason for not having options for accepting all priority marked messages, | ||
all exit messages, or all monitor messages as priority messages is the risk of | ||
introducing bugs when code in other modules are called from the process | ||
accepting priority messages. For example, if a process enables all monitor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this point should be emphasized. Disabling the message receive order guarantees should be opt-in and based on explicit agreement between sender and receiver (which may be the same module).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess when you say "the same module" you really mean "the same process"? 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I mean the same module. Say a gen_server
where an API function (called from outside the server process) ends up passing a priority message to the server process -- the code for both sender and receiver is in the same module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, ok, after re-reading the rest of the paragraph I get that. However, the significance of the module from which a call is made is unclear to me. Why does it matter? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only significance is that with both sender and receiver in the same module they are in a better position to agree on the validity of using priority messages, which otherwise would be totally invalid.
My point is that priority messages break long-standing Erlang semantics and are totally invalid in the general case. They must be opt-in, which requires a close relationship between sender and receiver.
eeps/eep-0076.md
Outdated
in the future might be modified in a way so that it relies on the selective | ||
receive optimization taking effect. Therefor I find it unacceptable to disable | ||
the selective receive optimization. The priority message implementation needs | ||
to be able to preserve the selective receive optimization. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say MUST not needs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've rephrased this.
* *Priority Marked Messages* - A message is marked as a priority message by the | ||
sender by passing the option `priority` in the option list that is passed as | ||
third argument to the `erlang:send/3` BIF. The receiver opts-in for reception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be an !
-like operator for sending messages prioritized (like, say, !!
)? Probably not, having a convenient operator may lead to abuse and/or over-use. Also, it would be somewhat hard to factor hypothetical priority levels into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want to encourage the use of priority messages that much. They should be rare enough to not need an operator.
6ed62ec
to
e90e422
Compare
third argument to the `erlang:send/3` BIF. The receiver opts-in for reception | ||
of priority marked messages from a specific sender by calling the | ||
`process_flag/2` BIF like this: | ||
`process_flag({priority_marked_message, SenderPid}, true)`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to allow something like this for allowing any process on the current node to send priority messages to the receiving process?
process_flag({priority_marked_message, local}, true).
Otherwise, for cases like overload protection where it may be a system-wide decision to change strategies, it could require having a secondary process used solely for the purpose of forwarding high priority messages to the receiving process based them opting in to receive priority messages from this secondary proxy process.
Demonstration the "priority proxy" thing:
-module(eep76_local_senders).
worker_start() ->
spawn(fun() -> worker_init(foo) end).
worker_init(Strategy) ->
% Option 1: spawn a "proxy" process
PriorityProxy = priority_proxy_start(self()),
erlang:process_flag({priority_marked_message, PriorityProxy}, true),
% Option 2: allow priority message from any local process
erlang:process_flag({priority_marked_message, local}, true),
true = erlang:register(worker, self()),
worker_loop(Strategy).
worker_loop(Strategy) ->
receive
{change_strategy, NewStrategy} ->
worker_loop(NewStrategy)
end.
priority_proxy_start(Worker) ->
spawn(fun() -> priority_proxy_init(Worker) end).
priority_proxy_init(Worker) ->
true = erlang:register(priority_proxy, self()),
priority_proxy_loop(Worker).
priority_proxy_loop(Worker) ->
receive
Message ->
erlang:send(Worker, Message, [priority])
priority_proxy_loop(Worker)
end.
change_strategy(Strategy) ->
spawn(fun() ->
% Option 1: send to a "proxy" process
erlang:send(priority_proxy, {change_strategy, Strategy}, [priority])
% Option 2: send directly to the worker process
erlang:send(worker, {change_strategy, Strategy}, [priority])
end).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that @Maria-12648430's suggestion could solve this by distributing a priority alias to the processes that should be able to send such priority messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double checking my understanding, that idea might look like this, right?
% receiver
PriorityAlias = erlang:alias([priority]).
% distribute to "senders" out of band
% sender (any process)
PriorityAlias ! priority_message_here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@potatosalad Yes
If you send priority messages fast enough, the process may never get to read normal messages again. This warrants a big warning in the documentation, or to make the implementation read from both queues. Considering the intended use case, the former sounds good enough. |
Yes, but I'd argue that you are misusing the feature if that should happen and quite a lot of features can destroy a system if misused (for example process priorities). Agree about the warning. |
In some scenarios it is important to propagate certain information to a process quickly without the receiving process having to search the whole message queue which can become very inefficient if the message queue is long. This EEP introduces the concept of priority messages to the language which aim to solve this issue.