How to Avoid Dropping Messages When a Monitor Restarts a Process?

I’m following along in the Learn You Some Erlang book and have gotten to the Errors and Processes section where it’s going over monitors, named processes, and restarting processes. At the end it mentions race conditions where you may send messages, the server dies, and you never receive a response. But it kind of just leaves it there.

I may be getting ahead of myself and will find some ways to handle these race conditions further on, but i’m stuck on it.

Here I have a pingpong server that will respond with pong if it gets a ping message. It will also exit if it gets a die message. Both can be configured with timeouts. I also have a monitor that will restart the pingpong server and register it to pingpong_server if it does die.

-module(pingpong).
-export([start_mon/0]).
-export([ping/0, ping/1, die/0, die/1]).
-export([race/0]).

%% Monitor

start_mon() ->
  {Pid, Ref} = spawn_monitor(fun() -> listen() end),
  register(pingpong_server, Pid),
  receive
    %% Restart the pingpong server
    {'DOWN', Ref, process, Pid, _} ->
      demonitor(Ref),
      start_mon()
  end.

%% PingPong Server

listen() ->
  receive
    {From, Ref, ping, T} ->
      timer:sleep(T),
      From ! {Ref, pong},
      listen();
    {die, T} ->
      timer:sleep(T),
      exit(kill)
  end.

%% Helpers

die() -> die(0).
die(T) -> pingpong_server ! {die, T}.

ping() -> ping(0).
ping(T) ->
  Ref = make_ref(),
  pingpong_server ! {self(), Ref, ping, T},
  receive
    {Ref, pong} ->
      io:format("pong~n");
    O ->
      io:format("got something else ~w~n", [O])
  after T + 3000 ->
    timeout
  end.

race() ->
  die(1000),
  ping(3000).

Then to use it I spawn the monitor:

Monitor = spawn(fun() -> pingpong:start_mon() end).

And can use the helper functions.

pingpong:ping().
> pong

pingpong:die().
pingpong:ping().
> pong

This all works as expected and the pingpong server will be restarted by the monitor if i kill it. But i created the race function that will send a {die, 1000} message followed by a {..., ..., ping, 3000} message so that the pingpong server will die before responding to the ping.

In this situation, is there a mechanism to carry the ping message over to the new procs mailbox or is this something that needs to be handled by the sender?

2 Likes

Sender either needs to handle it or you use another in-between process to handle it. Messages are potentially lossy, hence why everything should have a timeout. :slight_smile:

2 Likes