[erlang-questions] Message send guarantees

Raimo Niskanen raimo+erlang-questions@REDACTED
Mon Jan 30 13:26:26 CET 2017

On Fri, Jan 27, 2017 at 01:46:53PM +0300, Andrey Tsirulev wrote:
> Hello,
> 26.01.2017 10:14, Raimo Niskanen wrote:
> > On Wed, Jan 25, 2017 at 11:06:05PM +0000, Dmitry Kakurin wrote:
> >> No you cannot assume that. The message is considered "in transit" until the receiving process inspects it somehow.
> >>
> >> What aspect of implementation can cause such reordering? Could you give an example how this could happen? Maybe I'll be able to artificially create conditions where it would not happen. Or work around it in some other way. Please see below why.
> > On a multi-threade system it is very hard to know in which order things
> > happen, so there is no "reordering" since there is no temporal order
> > to begin with.
> What about the following example?
> A -- msg1 ---> A
> A -- msg2 ---> B
> B -- msg2 ---> A
> In this case, is it guaranteed that if both msg2 and msg1 get to A's msg 
> queue, msg1 gets there earlier?

It may be that in the current and all previous implementations msg1 is read
before msg2, but it is not _guaranteed_?

We had a little discussion and the VM guys after 2 minutes started suggesting
possible implementations that could cause msg2 to be read before msg1...

http://erlang.org/doc/apps/erts/communication.html 2.1, second paragraph:

    The only signal ordering guarantee given is the following: if an entity
    sends multiple signals to the same destination entity, the order is
    preserved; that is, if A sends a signal S1 to B, and later sends signal
    S2 to B, S1 is guaranteed not to arrive after S2.

> If this is guaranteed, what makes this example *really* different from 
> the original example?
> I use this pattern for delayed gen_server's initialization if it's time 
> consuming, like that:
> init(Args) ->
>      self() ! {init, Args},
>     ...
> handle_info({init, Args}, State) ->
>    %% time consuming initialization here
> to return from init ASAP so that start/start_link do not block for a 
> long time. Then I expect that after
> P = gen_server:start_link(...),
> P ! test
> when test is received, gen_server is fully initialized.  It never caused 
> problems, but it might be luck.

I'd say that is luck ;-)  In this case you might get a message from any
client that arrives before your {init,Args} message.

This sounds like a use case for proc_lib:spawn..., proc_lib:init_ack/1,2,
and gen_server:enter_loop/3-5.  Using these you can send an early init_ack
to the supervisor, do your time consuming initialization, and then enter
the gen_server receive loop when you are ready for the first message.

Another way could be to use gen_statem and start in an init state where you
postpone all messages until you get your {init,Args} message (there could be
a reference() in that message just for fun), do your time consuming
initialization and change states to running.  Or, of course, design your
own event queueing before handling the {init,Args} message.

> Best Regards,
> Andrey

Best Regards

/ Raimo Niskanen, Erlang/OTP, Ericsson AB

More information about the erlang-questions mailing list