{
"$type": "site.standard.document",
"canonicalUrl": "https://deterministic.space/writing-a-daemon.html",
"path": "/writing-a-daemon.html",
"publishedAt": "2019-09-24T00:00:00.000Z",
"site": "at://did:plc:x67qh7v3fd7znbdhauc45ng3/site.standard.publication/3mjcd2t6afe25",
"textContent": "Despite my best efforts,\nI end up logging into Linux servers and checking how they're doing\nway too often.\nIn recent projects\nI've also been responsible for adding way too many [.service] files\nand making sure they work.\nAll of that was based on a vague understanding of how systemd works,\nwithout ever _really_ looking into the finer details\nand the constant feeling that there are a lot of features I was missing.\nWith this post,\nI want to explore some of these aspects\nand figure out how to write better daemons.\nSee it as a set of notes\non the things I want to at in more depth.\n\n[.service]: https://www.freedesktop.org/software/systemd/man/systemd.service.html\n\nProper status updates\n\nServices can let systemd know what their internal state is,\nand to have it restart them when they don't respond.\n\nReadiness\n\nAs far as I can tell,\nby default, systemd services are of type simple,\nand are assumed to be ready immediately after they are started.\nThis might not be the case for a program that requires some time to start up,\nor that waits for a connection to be initialized.\n\nTo allow the service to notify systemd of its state,\nyou need to set the type to notify:\n\nTo tell systemd that the service is ready, you trigger a notification.\nThe easiest to test with is:\n\n(Note that you'll also need to set NotifyAccess=all in your Service section\nto allow sending status updates from subprocesses.)\n\nIn a real service,\nyou'd call [sd_notify] (or [rust-notify] in Rust)\nwith a string starting with READY=1.\nThis string can contain various newline delimited values,\nas described in the Description section [here][sd_notify].\nYou can, for example, append STATUS=Good to go!.\n\nSending RELOADING=1 and STOPPING=1\nwill tell systemd that the service is reloading or exiting respectively.\n\nIf your service is running in Notify mode,\nits [environment variables] contain NOTIFY_SOCKET\nwhich is set to the path to the notify socket\n(e.g. /run/systemd/notify).\n\n[systemd-notify]: https://www.freedesktop.org/software/systemd/man/systemd-notify.html\n[sd_notify]: https://www.freedesktop.org/software/systemd/man/sd_notify.html\n[rust-notify]: https://docs.rs/systemd/0.4.0/systemd/daemon/fn.notify.html\n[environment variables]: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Environment%20variables%20in%20spawned%20processes\n\nHealth\n\nThe same notification system can also be used to\nlet systemd make sure your service is doing fine.\nSpecifically, by adding something like WatchdogSec=5,\nsystemd will expect you to send WATCHDOG=1 notifications\nless then every 5 seconds.\n\n[watchdogs]: http://0pointer.de/blog/projects/watchdog.html\n\nLogging\n\n[journald] allows structured log messages,\nand using [slog-journald] (for example)\ncan set common [fields][journal-fields] automatically.\n\nIf systemd runs your service with journald set up,\nits [environment variables] contain JOURNAL_STREAM.\n\n[journald]: https://www.freedesktop.org/software/systemd/man/systemd-journald.service.html\n[journal-fields]: https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html\n[slog-journald]: https://github.com/slog-rs/journald\n\nSockets\n\nYou can define the sockets your services will consume\nand let systemd manage them for you.\nThe advantages are:\n\n1. Your socket will stay alive even through service restarts\n (if I understand correctly)\n2. You can set your service to only start once there is traffic on the socket\n (\"[socket activation]\", also used by macOS' launchd for example)\n\nThe easiest way is to define a [.socket] file\nwith the same name as your [.service] file.\nUsing the [listenfd] crate,\nyou can then quickly get the socket(s) available.\n\n[.socket]: https://www.freedesktop.org/software/systemd/man/systemd.socket.html\n[socket activation]: http://0pointer.de/blog/projects/socket-activation.html\n[listenfd]: https://crates.io/crates/listenfd\n\nLimiting Capabilities\n\nBy default,\nyour services run in an environment similar to just executing them with bash\nas the correct user.\nThat is convenient to get stuff running,\nbut might be a bit much if you're security conscious.\nThey are, however, a bunch of neat things you can set\nto limit what your process can do.\nHere's a few examples:\n\nMore in [this post][security]\nand the docs for [systemd.exec].\n\n[security]: http://0pointer.de/blog/projects/security.html\n[systemd.exec]: https://www.freedesktop.org/software/systemd/man/systemd.exec.html",
"title": "Notes on proper systemd services",
"updatedAt": "2019-09-24T00:00:00.000Z"
}