Daemonizing Common Lisp services.

Update (2016-06-09): During a discussion on Reddit I realised that the issues discussed in this post are not relevant to the systemd init system. At the time of writing my servers run Ubuntu 14.04 which uses Upstart as the init system. Upstart detaches the tty of the started services. That is the cause of the issues discussed below. Most Linux distributions seem to migrate to systemd as the init system. systemd does not detach the tty, it binds stdin to /dev/null and stdout and stderr to a logging stream. If your OS uses systemd you can turn a foreground application into a service without using GNU Screen or the daemon package.

Deploying a Common Lisp server application in production requires that it runs as a daemon.

A Unix init system like Upstart or systemd can be used to ensure that the service is always running. In this case the application can daemonize itself or it can run in the foreground and let the init system take care of daemonization.

It is usually easier to create an init script for a self-daemonizing application but then the source code gets more complicated.

When the application runs in the foreground the init script is slightly more tricky but the application is easier to debug.

Self-daemonizing

The procedure to daemonize an application is well documented but most of these documentation is focused on C. To implement the complete procedure in Common Lisp can become a mission in itself because it involves forking and opening and closing standard IO stream at the right times.

The daemon package implements all the necessary steps and provides a trivial API for daemonizing a program.

Though daemon is easy to use, all the forking makes it difficult to get backtraces when something goes wrong. The application then appears to be hanging while it is actually waiting in the debugger for input but the debugger can’t be used because standard IO is closed.

When a service daemonizes itself it is advisable to devise some method to interact with the application while it is waiting in the debugger. One of the swank libraries could be useful.

Run in foreground

Foreground applications can be used as-is for a service but it can not be used as the main application instantiated by the init system.

During the daemonizing process the init system closes all the standard IO streams. This causes the REPL to exit and the application to end.

GNU Screen can be used to keep the standard IO open for a daemonized service. However, when an error occurs one is in much the same situation as with a self-daemonizing application. The application appears to hang because it is waiting in the debugger but the debugger can’t easily be reached.

Screen has options to log standard IO to a file. Debugging then consists of killing the service and working through the logged backtrace. This is not ideal but it has the advantage of not introducing any code complexity in order to make a daemon.

Like in the self-daemonizing case, a swank library can be used to get live debugging back.

Comparing the options