How to use daemontools

How to use daemontools

Bernstein’s Daemontools are one way to keep a program running and
automatically restart it if it crashes. It is a very simple tool,
however, there are certain things I would have like to know when using it.
My knowledge shared here is based on Debian, where you can install
the daemontools using apt-get.

The basic principle is simple. You create a folder in /etc/service
with a script called run. The run script can then start other programs.

Typically, you also add a script to define the behaviour of the log output.
The common practice there is to add a log folder with another run script in there.

/etc/service/redis
├── log
│     ├── run
└── run

To give you an example, here the run script for redis:

#!/bin/sh
#
exec setuidgid redis sh -c '
  exec /usr/bin/redis-server /etc/redis/6379.conf
'

You see, it is a normal shell script.
The setuidgid command set the user used for execution. The redis
server is then simply started using the /etc/redis/6379.conf.

The log/run script is this:

#!/bin/sh
PATH=/usr/local/bin:/usr/bin:/bin
exec setuidgid youruser sh -c '
  exec multilog t s999999 n20 '!tai64nlocal' /path/to/your/preferred/log/destination
'

Here we are using the multilog command, also part of daemontools.
I will not go into the details of this command, see here for mor
information.

Once you have set up the directory with the run script, you can manage your
service using the dameontools (you might need to run it using sudo):

svc -u /etc/service/YOURSERVICE/     # start your service (-u = up)
svc -d /etc/service/YOURSERVICE/     # stop your service (-d = down)
svc -t /etc/service/YOURSERVICE/     # restart your service
svstat /etc/service/YOURSERVICE/     # Checks the status of your service

You can find all commands here on the official documentation.

Gotchas

Environment variables

Part of daemontools is also the envdir program to set environment variables. However,
I found it easier to simply export the needed variables within the run script. To give
you an example, here my run script for puma, a ruby webserver:

#!/bin/sh
#
export secret_key_base=abc...
export RAILS_ENV=production
export RBENV_ROOT=/home/plusandmore/.rbenv
export RBENV_VERSION=2.2.0

cd /your/railsapp/current
exec setuidgid plusandmore sh -c '
  exec /home/youruser/.rbenv/shims/bundle exec puma -e production -C config/puma.rb 2>&1
'

You see, I first export all environment variables needed to run the puma server.
The command to run puma is the normal puma command, with a few options set.

Don’t use daemons

Do not start a daemon within your run script. Otherwise, daemontools
tries to start your service every second, because it thinks your service has crashed.
You might use fghack, but I have not tried it.