So I have learnt a new thing recently, processes spawned in an IEx shell are not terminated after IEx exists, not even if they were started using link. The same obviously is not true for any two processes linked between them, and not even true for Erlang shells, so it is really about IEx only.
When inspecting the processes I can see that the link just disappears and the “child” process is still alive after IEx process (which was the “parent”) is long gone.
I have been researching this, but could not find any Elixir, Erlang or C code pointing in this direction.
Does anyone have any idea how and where this is implemented ?
Found the explanation while discussing with Claude LLM, and the answer is as simple as possible: when shutting down IEx with “Ctrl + C” and “a” the process exits normally, so the link is not triggered, because it is not a crash.
Do you mean iex or connecting to a release like @jstimps did?
In the latter case it is normal. In the former case once iex stops that beam instance also stops, so it would be very surprising if something survives.
The behavior in the remote shell case is surprising to me personally, since my background is mostly in Erlang, in which it’s different. To demonstrate:
Terminal A:
~ ❯❯❯ iex --sname server # or `erl -sname server`
Erlang/OTP 27 [erts-15.2.6] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit]
Interactive Elixir (1.18.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(server@Mac)1>
Terminal B:
~ ❯❯❯ erl -remsh server
Erlang/OTP 27 [erts-15.2.6] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit]
Eshell V15.2.6 (press Ctrl+G to abort, type help(). for help)
(server@Mac)1> spawn_link(fun() -> timer:sleep(1000000000) end).
<0.127.0>
(server@Mac)2>
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
(l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
a
~ ❯❯❯ erl -remsh server
Erlang/OTP 27 [erts-15.2.6] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit]
Eshell V15.2.6 (press Ctrl+G to abort, type help(). for help)
(server@Mac)1> is_process_alive(pid(0,127,0)).
false
(server@Mac)2>
Coming from Erlang, I had a natural expectation that halting an iex remote shell would trigger links on processes that were started in that shell. My expectation turned out to be wrong, but I can see how this would end up causing unexpected system behavior during debugging sessions. I will attempt a PR to the iex docs to explain the behavior, as I don’t see anything in there currently (although I might have missed it!)
Ah - i was missing the part where the iex session was a remote connection (the VM is still alive) - if im understanding correctly.
Yeah, sorry, now I see that I forgot to mention it is all about remote shells, but even then I would say the IEx remote shell behaviour is not intuitive, although a friendly approach. We have found this approach because we were thinking how to start an ad-hoc memory cleanup process in production without it dying when we exit the remote shell, it was surprisingly easy
I have checked both codes, and the Erlang shell code explicitly kills the evaluator, so I guess it was more explicitly implemented to avoid hanging processes. Personally I welcome both approaches, maybe shells should support both approaches with clarity on which mode is currently active for the shell users.