diff options
Diffstat (limited to 'wiki/devops/self-daemonization-sucks.md')
| -rw-r--r-- | wiki/devops/self-daemonization-sucks.md | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/wiki/devops/self-daemonization-sucks.md b/wiki/devops/self-daemonization-sucks.md new file mode 100644 index 0000000..06cd033 --- /dev/null +++ b/wiki/devops/self-daemonization-sucks.md @@ -0,0 +1,77 @@ +# Self-daemonizing code is awful + +The classical UNIX approach to services is to implement them as "daemons", +programs that run without a terminal attached and provide some service. The +key feature of a classical daemon is that, when started, it carefully +detaches itself from its initial environment and terminal, then continues +running in the background. + +This is awful and I'm glad modern init replacements discourage it. + +## Process Tracking + +Daemons don't exist in a vacuum. Administrators and owners need to be able to +start and stop daemons reliably, and check their status. The classic +self-daemonization approach makes this impossible. + +Traditionally, daemons run as children of `init` (pid 1), even if they start +out as children of some terminal or startup process. Posix only provides +deterministic APIs for processes to manage their children and their immediate +parents; the classic daemonisation protocol hands the newly-started daemon +process off from its original parent process, which knows how to start and +stop it, to an unsuspecting `init`, which has no idea how this specific +daemon is special. + +The standard workaround has daemons write their own PIDs to a file, but a +file is "dead" data: it's not automatically updated if the daemon dies, and +can linger long enough to contain the PID of some later, unrelated program. +PID file validity checks generally suffer from subtle (or, sometimes, quite +gross) race conditions. + +## Complexity + +The actual _code_ to correctly daemonize a process is surprisingly complex, +given the individual interfaces' relative simplicity: + +* The daemon must start its own process group + +* The daemon must detach from its controlling terminal + +* The daemon should close (and may reopen) file handles inherited from its + parent process (generally, a shell) + +* The daemon should ensure its working directory is predictable and + controllable + +* The daemon should ensure its umask is predictable and controllable + +* If the daemon uses privileged resources (such as low-numbered ports), it + should carefully manage its effective, real, and session UID and GIDs + +* Daemons must ensure that all of the above steps happen in signal-safe ways, + so that a daemon can be shut down sanely even if it's still starting up + +All of this gets even more complicated if the daemon has its own child +processes, a pattern common to network services. Naturally, a lot of daemons +in the real world get some of these steps wrong. + +## The Future + +[Supervisord](http://supervisord.org), +[Foreman](http://ddhttp://cr.yp.to/daemontools.htmlollar.github.io/foreman/), +[Upstart](http://upstart.ubuntu.com), +[Launchd](https://developer.apple.com/library/mac/documentation/Darwin/Referen + ce/ManPages/man1/launchctl.1.html), +[systemd](http://www.freedesktop.org/wiki/Software/systemd/http://cr.yp.to/dae + montools.html), and [daemontools](http://cr.yp.to/daemontools.html) all +encourage services _not_ to self-daemonize by providing a sane system for +starting the daemon with the right parent process and the right environment +in the first place. + +This is a great application of +[DRY](http://c2.com/cgi/wiki?DontRepeatYourself), as the daemon management +code only needs to be written once (in the daemon-managing daemon) rather +than many times over (in each individual daemon). It also makes daemon +execution more predictable, since daemons "in production" behave more like +they do when run attached to a developer's console during debugging or +development. |
