I have written (and published) small Erlang library that helps with integrating your release with systemd
Features
The idea of this library is to port some parts of the libsystemd
into Erlang without need for NIFs. Currently implemented features:
-
Notify socket which allows for sending notifications to systemd. This for example allows blocking startup until our application is completely ready, so not only it started up, but is ready to do it’s work. Unfortunately the feature of saving FDs between runs (which would allow for restarting application without disconnecting users) is not currently possible, but will be probably added as soon as Erlang stabilise
socket
interface instead ofinet
. -
Watchdog which allows systemd to watch for keep-alive messages via notify socket. This allows you to provide simple information to the systemd when it should restart your application before your failures hit the
init
process. -
Listen FDs which allow for socket activation of your application (i.e. application is started only when there is incoming data in socket) and keeping sockets opened between restarts. However while it is implemented it is currently pointless feature as you cannot use these
fd
s in any way due to fact thatgen_tcp
andgen_udp
requires unbind(3)
ed file descriptors. Maybe this will became more usable oncesocket
interface land. - Check for systemd booted system - pretty pointless, as all functionalities above are safe which mean that you can use all of above even on non-systemd OS and it will not (or at least should not) cause any problems. This was implemented just for functionality parity.
The best thing? It is mostly automagical. Watchdog and notify socket will be established without any user interaction. Only thing needed is to tell systemd that your application is ready (not possible to be done automatically unfortunately).
TODO in future:
-
journald
backend forlogger
(will be useful for Elixir 1.10+ as well, as this shares the logging implementation with Erlang)
Example
Just fetch repo on machine with systemd, and run make
(requires sudo
to setup systemd services). Then you can see that service is up and running:
hauleth@test-ubuntu:~/plug$ systemctl status example-watchdog.service
● example-watchdog.service - Example BEAM application that uses watchdog
Loaded: loaded (/usr/local/lib/systemd/system/example-watchdog.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2020-01-16 14:46:02 UTC; 3s ago
Main PID: 1662 (beam.smp)
Tasks: 20 (limit: 1108)
CGroup: /system.slice/example-watchdog.service
├─1662 /home/hauleth/plug/_build/prod/rel/plug_systemd_example/erts-10.6.2/bin/beam.smp -- -root /home/hauleth/plug/_build/prod/rel/plug_systemd_example -progname erl
├─1701 /home/hauleth/plug/_build/prod/rel/plug_systemd_example/erts-10.6.2/bin/epmd -daemon
└─1704 erl_child_setup 1024
Jan 16 14:46:01 test-ubuntu systemd[1]: Starting Example BEAM application that uses watchdog...
Jan 16 14:46:02 test-ubuntu systemd[1]: Started Example BEAM application that uses watchdog.
We simulate reload by curl http://localhost:4000/reload
:
hauleth@test-ubuntu:~/plug$ curl http://localhost:4000/reload
hauleth@test-ubuntu:~/plug$ systemctl status example-watchdog.service
● example-watchdog.service - Example BEAM application that uses watchdog
Loaded: loaded (/usr/local/lib/systemd/system/example-watchdog.service; enabled; vendor preset: enabled)
Active: reloading (reload) since Thu 2020-01-16 14:46:02 UTC; 2min 10s ago
Main PID: 1662 (beam.smp)
Tasks: 20 (limit: 1108)
CGroup: /system.slice/example-watchdog.service
├─1662 /home/hauleth/plug/_build/prod/rel/plug_systemd_example/erts-10.6.2/bin/beam.smp -- -root /home/hauleth/plug/_build/prod/rel/plug_systemd_example -progname erl
├─1701 /home/hauleth/plug/_build/prod/rel/plug_systemd_example/erts-10.6.2/bin/epmd -daemon
└─1704 erl_child_setup 1024
Jan 16 14:46:01 test-ubuntu systemd[1]: Starting Example BEAM application that uses watchdog...
Jan 16 14:46:02 test-ubuntu systemd[1]: Started Example BEAM application that uses watchdog.
And after 10 seconds it is “up” again:
hauleth@test-ubuntu:~/plug$ systemctl status example-watchdog.service
● example-watchdog.service - Example BEAM application that uses watchdog
Loaded: loaded (/usr/local/lib/systemd/system/example-watchdog.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2020-01-16 14:46:02 UTC; 2min 27s ago
Main PID: 1662 (beam.smp)
Tasks: 20 (limit: 1108)
CGroup: /system.slice/example-watchdog.service
├─1662 /home/hauleth/plug/_build/prod/rel/plug_systemd_example/erts-10.6.2/bin/beam.smp -- -root /home/hauleth/plug/_build/prod/rel/plug_systemd_example -progname erl
├─1701 /home/hauleth/plug/_build/prod/rel/plug_systemd_example/erts-10.6.2/bin/epmd -daemon
└─1704 erl_child_setup 1024
Jan 16 14:46:01 test-ubuntu systemd[1]: Starting Example BEAM application that uses watchdog...
Jan 16 14:46:02 test-ubuntu systemd[1]: Started Example BEAM application that uses watchdog.
We can also force it to restart by curl http://localhost:4000/stop
which will trigger Watchdog to restart application:
hauleth@test-ubuntu:~/plug$ curl http://localhost:4000/
1760
hauleth@test-ubuntu:~/plug$ curl http://localhost:4000/stop
hauleth@test-ubuntu:~/plug$ curl http://localhost:4000/
1846
Requests on /
return current PID of the VM, so we clearly see that the restart happened in the meantime.
If you are using systemd for supervising your application, then I highly suggest you to try it and see if this can improve your experience.