Skip to content

Instantly share code, notes, and snippets.

@grawity
Last active November 15, 2023 19:35
Show Gist options
  • Save grawity/6e5980981dccf66f554bbebb8cd169fc to your computer and use it in GitHub Desktop.
Save grawity/6e5980981dccf66f554bbebb8cd169fc to your computer and use it in GitHub Desktop.
systemd Type=notify implementations

The official documentation is in the sd_notify(3) manual page.

Very short summary:

  1. Change your systemd service to Type=notify.
  2. Your daemon will receive an environment variable NOTIFY_SOCKET, which contains a path to an AF_UNIX socket.
    (If the first path byte is @, this means an "abstract" socket, and you should change the 1st byte to 0x00 before using.)
  3. The protocol consists of sending datagrams containing textual (UTF-8) status messages.
    Each message contains newline-separated KEY=value parameters.
  4. When the daemon is ready, it must send READY=1, and systemd will transition the service from "starting" to "running".
  5. At any point, you can send STATUS=Some text and the text will be shown in systemctl status. You can use this to show e.g. current client count or other statistics. This can be combined with the above, e.g. READY=1\nSTATUS=All systems go!
use IO::Socket::UNIX;
sub notify {
my ($arg) = @_;
my $path = $ENV{NOTIFY_SOCKET} // return;
$path =~ s/^@/\0/;
my $sock = IO::Socket::UNIX->new(Type => SOCK_DGRAM, Peer => $path);
$sock->print($arg);
}
sub notifyv {
my (@args) = @_;
notify(join("\n", @args));
}
notify("READY=1");
import os
import socket
def notify(arg):
path = os.environ.get("NOTIFY_SOCKET")
if path:
if path[0] == "@":
path = "\0" + path[1:]
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.sendto(arg.encode("utf-8"), path)
def notifyv(*args):
notify("\n".join(args))
require 'socket'
def notify(arg)
path = ENV["NOTIFY_SOCKET"] || return
path = path.sub(/^@/, "\0")
UNIXSocket.open(path) do |sock|
sock.write(arg)
end
end
def notifyv(*args)
notify(args.join("\n"))
end
@glaszig
Copy link

glaszig commented Dec 4, 2022

UNIXSocket appears to open a stream but a dgram is wanted. the below works:

def notify(arg)
  path = ENV["NOTIFY_SOCKET"] || return
  Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM, 0).tap do |socket|
    socket.connect(Socket.pack_sockaddr_un(path))
    socket.close_on_exec = true
  end.write(arg)
end

https://gist.github.com/zimbatm/9f1bc26446af0ee3e5c5?permalink_comment_id=1902920#gistcomment-1902920

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment