[erlang-questions] Message send guarantees

Raimo Niskanen raimo+erlang-questions@REDACTED
Fri Jan 27 08:41:32 CET 2017

On Fri, Jan 27, 2017 at 02:25:49AM +0000, Dmitry Kakurin wrote:
> From: Joe Armstrong <erlang@REDACTED>
> Sent: Thursday, January 26, 2017 5:29 AM
> On Wed, Jan 25, 2017 at 12:38 AM, Dmitry Kakurin
> <dima_kakurin@REDACTED> wrote:
> > When I execute "pid ! msg" and it returns, what are the guarantees if pid
> > and self are on the same node?
> > Can I assume that by the time it returns, msg is in the pid's queue? And as
> > a result all messages sent to pid afterwards will be queued after msg?
> >
> > The reason I'm asking is because I need a guarantee of proper message
> > ordering in the following scenario when all processes involved are local to
> > a node:
> > 1. A --msg1--> C (process A sends msg1 to process C)
> > 2. A --msg2--> B
> > 3. B --msg2--> C (process B simply proxies msg2 from A to C)
> >
> > I need a guarantee that msg2 will always appear in C's queue after msg1.
> This cannot be guaranteed
> Thanks Joe and others. I understand now that it's fruitless to pursue a direction where I'd try to somehow artificially establish this guarantee.
> I have to re-evaluate my constraints then. All along my main constraint was that C can be any gen_server, it's not owned by me and I cannot change it.
> If I could change C then the following would work:
> 1. A --msg1--> C
> 2. A --ping--> C
> 3. A <--pong-- C
> 4. A --msg2--> B
> 5. B --msg2--> C

Have you changed your question?  Previously the problem was to send
non-proxied messages after proxied messages.

But if B is a message relay (receive Msg -> C ! Msg, loop() end),
and provided the ping/pong is a gen_server call (since the request
contains who should have the reply, then this should also work:
1. A --msg1---> B
2. A --req----> B
3. B --msg1---> C
4. B --req----> C
5. A <--reply-- C
6. A --msg2---> C

> All we need from C is to respond "pong" to "ping" message. In this case A knows msg2 is enqueued after msg1 because A has observed "pong" in response to "ping" that was sent after msg1. The ordering is as desired here.
> Now the only problem I have to solve is: what can be used as a benign message that I can send to any gen_server such that it would reply (to emulate ping/pong exchange above)?
> Looking thru gen_server source code I see that it's processing sys messages. So I can use get_state message as "ping" and response with state as "pong". Except it may not be really benign perf-wise if amount of state kept by C is significant.
> There is also get_status, but I don't understand how it's processed and if I can use it for ping/pong purposes. Can I? Is there a better message?

sys:get_status/1,2 returns much more data including what sys:get_state/1,2
returns, so it is less suitable.

If you know anything more about your gen_server C, it may have some status
quering handle_call that can be used.

Maybe sys:statistics/2 can be good enough.  Mostly no statistics collection is
activated for a given gen_server so you will get just {ok,no_statistics} back
as pong, and if statistics collection should be activated the gen_server
does not much more than process_info(self(), reductions) and erlang:localtime(),
which may and may not be regarded as heavy, but compared to returning the whole
arbitrary gen_server state it may be better.

> Do you have a better idea for ping/pong messages on C? Or how to solve this in general?
> Thank you, Dmitry.
> P.S. I know that in this simplified example I could piggyback on msg1 if it returns something but in real code I cannot, so let's assume it's a one-way message (a cast, not a call). So I'm OK with ping/pong.


/ Raimo Niskanen, Erlang/OTP, Ericsson AB

More information about the erlang-questions mailing list