How to use systemd notify
I'm learning how to use systemd notify. I'm thinking it is a kind of mechanism, which allows a process to send a notification to another process.
So, I tried to make a notification with the command systemd-notify --ready --status="hello"
. Then I got an error: No status data could be sent: $NOTIFY_SOCKET was not set
. It seems that it needs a listener, just like the socket. But I don't know how to make a listener to receive this notification.
Also, I've known that the service of systemd has some different types, one of them is notify
. The doc said, Type=notify: identical to Type=simple, but with the stipulation that the daemon will send a signal to systemd when it is ready.
. So it seems that the service whose type is notify can send notification too, but I don't know how to use it either.
The systemd-notify
tool is specifically meant to be used by a shell that runs as a systemd service using Type=notify
.
If you set up a service using Type=notify
, systemd will automatically set up a communication socket back to systemd and will export its path to the service under $NOTIFY_SOCKET
.
It will also listen for special messages in that socket, such as whether the service is ready (in which case systemd will transition it to status started
, since initialization is completed) and also the self-reported status of the service, which will also be reported in the output of systemctl status mytest.service
(assuming a service called mytest
.)
You can read the man page of systemd-notify
for all the details, even though there's a lot of complexity there... Perhaps the example at the end is useful in illustrating how it works.
Let's use that example for a hands-on experiment!
Create a script like the one below somewhere in your system, such as /usr/local/bin/mytest.sh
:
#!/bin/bash
mkfifo /tmp/waldo
sleep 10
systemd-notify --ready --status="Waiting for data…"
while : ; do
read a < /tmp/waldo
systemd-notify --status="Processing $a"
# Do something with $a …
sleep 10
systemd-notify --status="Waiting for data…"
done
I added some sleep 10
s so you can see what's happen, when watching the systemctl status mytest.service
output.
Make the script executable:
$ sudo chmod +x /usr/local/bin/mytest.sh
Then create /etc/systemd/system/mytest.service
, with contents:
[Unit]
Description=My Test
[Service]
Type=notify
ExecStart=/usr/local/bin/mytest.sh
[Install]
WantedBy=multi-user.target
Then reload systemd (so it learns about the unit) and start it:
$ sudo systemctl daemon-reload
$ sudo systemctl start mytest.service
Then watch status output, every so often:
$ systemctl status mytest.service
You'll see it's starting
for the first 10 seconds, after which it will be started
and its status will be "Waiting for data…".
Now write some data into the FIFO (you'll need to use tee
to run it as root):
$ echo somedata | sudo tee /tmp/waldo
And watch the status:
$ systemctl status mytest.service
It will show the status of the service as "Processing somedata" for 10 seconds, then back to "Waiting for data…".
If you were to write this code in C or another language that supports systemd bindings, you would use the sd_notify()
function for this purpose. If you're familiar with C, you might want to take a look at the sd_notify(3) man page.
Not a complete answer, but I got as far as this, using "netcat"
A) in one terminal session, do:
export NOTIFY_SOCKET=/tmp/test.sock
nc -l -U -u /tmp/test.sock
B) open another terminal session and do:
export NOTIFY_SOCKET=/tmp/test.sock
systemd-notify --read --status="hello"`
This works, but on the netcat
side you will get nc: connect: Invalid argument
. I don't know how to work around that.