Robert A. Uhl

Running Lisp as a Linux service

One of the truly wonderful things about programming in Common Lisp is that the system is complete interactive: the programmer can manipulate anything at run time, including the language itself. This is a really powerful technique — but how does one preserve the state of the system between reboots? And how does one get an image-based Lisp system to play nice with Linux’s system service model?

Well, John Wiegley published a great technique a few years ago which I’ve adapted for Tasting Notes. It’s remarkably simple: create a user to run the system as (just like other services like PostgreSQL or httpd); then create a standard init.d script to run the system. The really clever thing he does is start the system itself, a Swank listener and a kill port. Starting the system is self-explanatory, but what about the rest?

Swank provides a live connexion to a running Lisp system via which one can interact with the system’s internals. It’s pretty cool, and Wiegley’s method gets the job done. So far this is pretty standard stuff; I’ve used it in my own software.

The really clever bit is this bit of code here:

(sb-bsd-sockets:socket-bind socket #(127 0 0 1) *kill-port*)
(sb-bsd-sockets:socket-listen socket 1)
(multiple-value-bind (client-socket addr port)
    (sb-bsd-sockets:socket-accept socket)
      ((stream (sb-bsd-sockets:socket-make-stream client-socket
                                                  :element-type 'character
                                                  :input t
                                                  :output t
                                                  :buffering :none)))
    (princ "Saving core and shutting down … " stream) (terpri stream))
  ;; Close up the sockets (sb-bsd-sockets:socket-close client-socket)
  (sb-bsd-sockets:socket-close socket))

What this does is wait until someone connects to *KILL-PORT*, then proceeds to shut down the system, kill all threads and cleanly exit. Smart and very simple: all the shutdown script has to do is telnet $KILL_PORT and the software shuts down.

Finally, it calls SB-EXT:SAVE-LISP-AND-DIE to save the current Lisp environment to a file; the next time it starts up it will run that image, so the software’s complete history is saved.

All in all, extremely nifty; I ported Tasting Notes to start using it this weekend.

06 February 2018: removed link to Tasting Notes & update URL