Notes on Deploying Common Lisp Web Services

Posted by David Gu on March 27, 2017

I’m recently finishing a Common Lisp web service used inside a company. An essential part of the reason why I choose Lisp in this case is, CLOS, one of the most powerful tools for designing complicated concepts. It’s a nice experience using CLOS to successfully solve some hard problems along with extending some components.

However, the embarrassing thing is I’ve never delivered a web application before, all I know is developing, debugging within SLIME and writing some scripts to deliver a binary executable so far. Web applications, however, are long-running services (or better said, “processes”). Once the services are started, you’d wish there are some tools to stop or restart them, basically. And if the service crashes somehow or the machine just has restarted due to some maintenance, it would be wonderful that the service itself could restart automatically. In this article, I therefore try to introduce two solutions that may just work for whoever is or will be searching for similar questions on the Internet.

1. TMUX

tmux1 is a software application that can be used to multiplex several virtual consoles, allowing a user to access multiple separate terminal sessions inside a single terminal window or remote terminal session. Before I got used to Emacs, I used tmux way much more to manage sessions on Linux. After all, Emacs is just an editor, no matter how much I love it. By using tmux, one can attach/detach sessions in an absolutely sane way. So, here are some recipes.

1.1 for creating a new session

$ tmux new -s session-name

1.2 for attaching a session

$ tmux a -t session-name

1.3 for detaching from a session

$ tmux detach 
# or use the shortcut
$ Ctrl-b d

1.4 for killing a session

$ tmux kill-session -t session-name

1.5 for sending keys to a session

$ tmux send-keys -t session-name "(+ 1 2 3)" C-m

One might be curious what does send-keys subcommand do exactly. In the above example, first imagine we already have a session where SBCL got started, tmux then sent an expression (+ 1 2 3) to Lisp followed by a new line which is indicated by C-m:

Now you can see, by using send-keys, one can write shell scripts to start, stop, reload (fasl files), restart lisp services or just send any expressions to evaluate without putting too much efforts into it. For more information about tmux’s commands, please check its manual.

2. Supervisor

tmux is both powerful and flexible, however, it can not tell us (through, for example, logging) if the server crashed or even restarted itself automatically after an unexpected crashed. We thus need some sort of processes management tool.

Supervisor is a client/server system that allows its users to monitor and control a number of processes on UNIX-like operating systems.2 This is a piece of Python software, and it is for Python 2.x only. I’m definitely not the first one who came up with using this tool, as a matter of fact, way back at 2013, Fukamachi wrote an essay talking about how he managed to deploy Quickdocs3 web services. In that paper, Supervisor along with Nginx are proposed, and Clack, a piece of software written by himself was used as well.

Fukamachi didn’t write the essay in English, unfortunately, but it’s not hard to understand what he proposed. Basically, one can prepare a Makefile like this to start the service:

SERVER_PORT=8000
SWANK_PORT=4005

define sbcl
	sbcl --noinform --disable-debugger \
		--load /home/david/quicklisp/setup.lisp \
		--eval '(progn $1)' \
		--eval '(progn $2)'
endef

start:
	$(call sbcl, \
		(ql:quickload :lucerne-hello-world) (ql:quickload :swank), \
		(lucerne:start lucerne-hello-world:app :port $(SERVER_PORT)) \
		(swank:create-server :port $(SWANK_PORT) :style :spawn :dont-close t))

Then define your service in supervisord.conf:

[program:lucerne]
command=make -f /paht-to-your-Makefile/Makefile start
directory=/your-project-path
numprocs=1
autostart=true
autorestart=true
user=david
redirect_stderr=true
stdout_logfile=/var/log/supervisor/lucerne-hello-world.log

For more information about how to use Supervisor, please check its documentation which is very comprehensive and easy to understand. The last thing I want to discuss is, within the above Makefile example, one may notice that we start a swank server besides the Lisp web service. Supervisor can indeed monitor services, but what about if we want to compile lisp code even when the service is running? That is, we don’t want to issue sudo service supervisor restart but just re-compile and load pieces of fasl files into the original Lisp image and keep it running. Within Emacs, one can manage to achieve that goal by issuing M-x slime-connect 127.0.0.1 40054 and then start to re-compile (C-c C-c) definitions or just inspect and debug, dynamically. In the end, one can even connect to a Lisp image which is deployed at a remote machine. Please check the documentation at this page.

  1. Wikipedia, tmux, https://en.wikipedia.org/wiki/Tmux 

  2. Supervisor: A Process Control System, http://supervisord.org 

  3. Quickdocs, Library Documentation Hosting for Common Lisp, http://quickdocs.org 

  4. If your specified the port 4005 for swank, of course.