Ctrl-g q in dev and GenServer termination

Hi,

This has probably been asked a gazilion times…

Is there a reilable way to trap the stop of a GenServer in development, that means when you either stop using ctrl-g q or ctrl-c ctrl-c?

What I have tried:

  • Process.flag(:trap_exit,true) in init/1, with terminate/2
  • Process.monitoring from init/1 and handle_info/2
  • Spawning a process that monitors with receive

None of them worked.

On start of the GenServer I am registering with an external site and I want to unregister on stop.

This is only for development.

1 Like

I believe those shortcuts halt the machine.

You can stop with System.stop which will be clean, but otherwise no, I don’t think you can.

I believe you can add a custom handler for SIGTERM but not SIGINT.

Yeah I figured.

I am adding this to my .iex.exs:

defmodule MyIEX do
  def exit, do: System.stop()
end

import MyIEX

Now I just have to remember to type exit when I quit.

Thanks.

2 Likes

You can also exit with Ctrl + \ (this sends SIGQUIT).

I’ve found it to be a more graceful way of exiting. Perhaps this may work for you?

1 Like

Is there a way to map Ctrl + d to that, to get standard REPL exist behavior?

My guess is that if you can find a way to pass a SIGQUIT signal to the terminal, and map that to Ctrl + d, that would would work. Not sure how to do that though.

FYI the Ctrl + \ keyboard shortcut is not specific to IEx/erl shell, I believe it is a behavior of the terminal emulator. You can use it to quit e.g. the Python shell, for example. So it’s handy to know outside of this specific context.

1 Like

From iex you can do :erlang.exit(pid(0,0,0), :kill) which will unconditionally terminate the system but generate a crash dunp in the file erl_crash.dump. Don’t ask :wink: :grinning_face:

6 Likes

Is it hardcoded somewhere that init is pid(0,0,0)? Or does it happen naturally that the mother of all processes just registers first and gets the zero-nth pid number?

The init module is preloaded into the BEAM and is the module that is automatically run by the BEAM when it starts its first process, the one that is <0.0.0>, calling the function init:boot(BootArgs) and the first thing it does is to register itself under the name init. It then traps exits. Note that although it a “special” process in how it is started and the module it runs it is actually just a normal Erlang process which is why you can kill it by sending it kill signal which is untrappable.

Actually all ALL processes in Erlang are equal and there are no special processes in any sense. Erlang is a very egalitarian in system in the sense that there are no special process and no special modules. All processes are equal and all modules are equal. You can kill or delete anything. :wink: :grinning_face:

5 Likes

Hey ! Thank you. Yes I know all processes are treated equal, the “mother of all processes” was a joke, though it’s kinda true right ? If it’s the only process at the beginning, all other processes must have been spawned by this one or one of its spawns. Or the BEAM can also start other processes after boot?

Regarding the <0.0.0> process, it the pid number a simple counter that starts at zero, and the first process just gets that first number? Or is that pid enforced by other means? Spawning repeatedly generally yields increasing pid numbers so I have always assumed it was just a counter.

1 Like

No, not really. It is really just a reference to the internal data defining the process. The only number which has any real significance is the first one.
Way way back in the the old days the 2nd number was an index into a process table and the 3rd number was the number of time this index had been used. This to keep pids unique. Now they don’t mean that, again you really can’t read much out of them.
The 1st number indicated whether the pid referenced a long process or a process on another node: 0 on the local; any other number another node. You couldn’t get any info from the number on which node it was, just not this one. That is still valid. So <0.0.0> says this is the pid of a local process, and we know it is the initial process.

1 Like

Alright, thank you! It’s so nice to have you on the forum :slight_smile:

(edit for below in order not to spam: yay! so indeed there is a counter increment, which makes sense given pids generally have growing middle numbers – thank you :))

Sorry I wasn’t quite right here, for correct info check

2 Likes

@rvirding

I’m curious about the design decisions around process relationships in Erlang. Was there ever consideration for building parent-child relationships directly into processes at the VM level, similar to how POSIX maintains process trees with PPIDs?

I understand this can be achieved through supervisors and the OTP supervision tree, but I’m wondering if the core VM design ever included native parent-child tracking for all processes, or if the decision was made early on to keep the process model simpler and handle hierarchical relationships at the application level instead.

1 Like

From the very beginning processes did not have built parent-child relationships. It did keep processes very simple and it allowed us to work on how to build systems. The ideas of how to structure systems developed as our understanding of the problem grew and what was needed to build reliable systems that could handle errors in the right way.

We were working together with another group in Ericsson who were looking at designing a new architecture and used Erlang for experimenting. As they were very knowledgeable about such systems they came back with comments and ideas about how they thought they should look and work and what Erlang needed. Out this grew error handling and what later became supervisors. They also actually developed the first system Ericsson using Erlang!

Note that these ideas evolved before OTP was built and most of the ideas that became formalised and described in OTP came from these ideas. For examples we had of course servers before we got OTP gen_server and we were managing processes and restarting them when necessary before we had supervisors.

One very good thing with OTP is that they “packaged” these things and bought order into the whole library and system structure. This is an ENORMOUS benefit when building systems. You cannot overate it.

12 Likes