Announcing the sd-notify crate
2022-01-12This is a quick post announcing the sd-notify
crate. sd-notify
is a Rust library for interacting with systemd
or a compatible service manager.
If you're not running Linux or you don't like systemd
, this crate is not for you.
systemd in 3 minutes
Assuming you are running systemd
, at some point you might find yourself with a program you want to automatically run on start-up. Historically, this meant doing an intricate dance which includes calling fork()
twice and writing your PID to a file, but fortunately, with systemd
this is no longer required and is actually discouraged.
You can take your plain console application and make a systemd
unit for it:
[Unit]
Description=Monitors room temperature
[Service]
User=stats
ExecStart=/usr/local/bin/monitor-temperature
Restart=on-failure
RestartSec=10
[Install]
WantedBy=default.target
You then drop that file under /etc/systemd/system/monitor-temperature.service
, run systemctl daemon-reload
, systemctl enable --now monitor-temperature
and you're done.
For the effort, you get logs (journalctl -efu monitor-temperature
), precise child process tracking (using control groups), CPU, memory and I/O accounting, automatic restarts, and a way to manage your service across all the popular Linux distros.
systemd start-up types
If your daemon has a long start-up sequence, systemd
can tell you whether it is ready or not. In order to do that, you can set the Type
clause.
The simplest, and also the default, option is called simple
. It means that the daemon is marked as ready right after it starts. Another useful option is forking
, which means that the service does the classic double-fork dance. You can read more about these two (any many others) in your systemd.service
documentation page.
What the sd-notify
crate helps with is the notify
start-up type. This lets you do whatever initialization you want, then notify systemd
that you are ready by sending a over a Unix socket. Services can also say that they are reloading their settings, stopping, or even set a status message. The protocol is described in detail here.
Using sd-notify
The basic usage is quite simple. You do your initialization steps, then call:
let _ = sd_notify::notify(true, &[NotifyState::Ready]);
That's all and now your daemon only shows as "running" when it finished starting up.
$ systemctl status monitor-temperature
Active: activating (start) since Wed 2022-01-12 20:36:02 EET; 9s ago
[snip]
$ systemctl status monitor-temperature
Active: active (running) since Wed 2022-01-12 20:36:12 EET; 2s ago
[snip]
You can also include a status message:
let _ = sd_notify::notify(
true,
&[
NotifyState::Ready,
NotifyState::Status("Monitoring room temperature"),
],
);
$ systemctl status monitor-temperature
Active: active (running) since Wed 2022-01-12 20:41:46 EET; 782ms ago
Status: "Monitoring room temperature"
[snip]
There's also one advanced feature: you can retrieve file descriptors passed by the service manager, for socket-activated daemons. You can read more on it here.
Final words
sd-notify
is written in pure Rust, has no dependencies and is available under a permissive license (MIT or Apache-2.0). My intention is that it stays lightweight, but I'm not necessarily opposed to adding more features.
If you want more functionality today, try the libsystemd
or rust-systemd
crates.