leostera / reactor

🚀 Native Actors for Reason and OCaml
70 stars 5 forks source link

Support Links and Monitors across Processes #9

Open leostera opened 5 years ago

leostera commented 5 years ago

Right now it's impossible to know when an actor has been terminated from an observing actor, unless the terminated actor notified the observing actor directly.

To solve this, we can implement the well known link and monitor pattern that Erlang has proved to make work.

The idea behind monitors is that any process can create a monitor towards a Pid, and they will then receive a message whenever that Pid is terminated.

let observed_pid = spawn( (_, _) => `Terminate, ());
let observer = spawn( (ctx, monitor_ref) => {
  switch(monitor_ref) {
  | None => `Become( monitor(ctx.self(), observed_pid) )
  | Some(mon) => 
    switch(ctx.recv()) {
    | Some(`System(`DOWN(mon_ref, pid, reason))) => 
      Logs.app(m => m("Our process has died! We can still continue now."));
      `Become(None);
    }
    | _ => `Become(monitor_ref)
  };
}, None);

Similarly for links, a linked process is spawned to be linked to another, so that if one goes down, so does the other:

let count_down = (_, n) => {
  switch(n) {
  | 0 => `Terminate;
  | _ => `Become(n-1);
  }
};

let linked_pid = spawn(count_down, 10);
let b = spawn((_, link) => {
  switch(link) {
  | None => `Become( link(ctx.self(), linked_pid) )
  | Some(_) => 
    switch(ctx.recv()) {
    | Some(`System(`EXIT(pid, reason))) => 
      Logs.app(m => m("Our process has died! I shall die now too."));
      `Terminate;
    }
    | _ => `Become(link)
  };
}, None);

Note that links force you processes to die together in order, but monitors just notify. Of course you can build links on top of monitors so we may consider doing so.