Are PID:s movable between nodes?

I’ve understood PID:s change when they pass a node barrier. I.E, PID 0,2,2 on the local node A is automatically translated to I.E. 5.2.2 on a remote node B.

Can then node B pass the PID to node C, which will then answer node A? Or will the PID reference break on the last transfer?

And if it works, do I need to pay any special attention to the case when C gets the message on startup, possibly before fully discovering node A?

I’ve been doing experiments on this inside a bigger application, but I’ve been having such mixed results, I’m starting to suspect any success is accidental, not at all by design


One of the major benefits of the BEAM is that you do not need to care if a process runs on your own machine or remote if you know its name or PID, so everything should be fine.


Allright. Any idea about why I’m occasionally, when doing Process.monitor() on node C, sometimes (more often in a larger cluster) get a {:DOWN … :noproc} reported?

1 Like

Because that process ceased to exist? That’s the only possible explanation for a :noproc according to the documentation of :erlang.monitor/2


I read that too. Yet, the process is clearly running (it’s also monitored locally under node A, and that monitor did not trigger)

I’m thinking, another possible explanation to be, because the node is not known to the other node right now (for some reason)?

For example, Process.monitor(,2,1)) will also trigger :noproc, not distinguishing between “process is actually confirmed to not be running at node” and “node not known/connected”?

1 Like

Check out what is the result of, 2, 1), it may be a local pid if it cannot create a remote one. In such cases, :noproc makes sense.

If you give actual node names though, you can see :noconnection:

$ iex --sname bar
Erlang/OTP 18 [erts-7.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Interactive Elixir (1.5.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(bar@macbook-2)1> Process.monitor({:foo, :bar})
iex(bar@macbook-2)2> flush()
{:DOWN, #Reference<>, :process, {:foo, :bar}, :noconnection}

You are correct. I wrongly assumed that were a direct struct initializer.

I’ve gotten it all working now, with some extra calls to :global.sync regularly. Not sure exactly why that helped, though.

As a side-note; I think I’ll be moving the entire design to named processes instead. It wasn’t feasible a couple of weeks ago, but has since become a very reasonable redesign.

Thank you for the clarification!

1 Like