Supervisord is a well-known tool among developers for controlling processes. It’s especially useful for monitoring process status and restarting on a crash. For a long time, I used supervisor on my personal projects and still using it at work. But while migrating HastaTakip from Ubuntu 14.04 to Centos 7, I made a different choice for process monitoring and controlling:systemd.
Well…I’m sure you heard about systemd before. It’s the controversial software that landed to Linux environment in 2010 and replaced System V init system. Its name is enough to flame wars between Linux users. I don’t like some of the features introduced by systemd, like binary logs, network interface names etc. but let’s face the fact–systemd is here to stay. So I think we should get familiar with it and harness it’s useful features to our benefit.
supervisord as a process supervisor
Let’s say I have a Django application named
Foo. I want to be sure
running all the time, even if it crashes. Also, I want a simple interface to
start, stop and restart its process.
Supervisord is a perfect match for this
[program:foo] command=/home/foo/bin/start_foo user=foo environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8
supervisord.conf above I can control process easily:
$ supervisorctl status foo $ supervisorctl stop foo $ supervisorctl start foo $ supervisorctl restart foo
Let’s say I have some background tasks to do upon request and I want to use Celery for this. Now I have two processes to monitor and control.
[program:foo_django] command=/home/foo/bin/start_foo user=foo environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8 [program:foo_celery] command=/home/foo/bin/start_celery user=foo environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8 [group:foo] programs=foo_django,foo_celery
$ supervisorctl status foo:* $ supervisorctl stop foo:* $ supervisorctl start foo:* $ supervisorctl restart foo:*
Almost two years of using supervisor I didn’t need any other command or option.
It’s simple and gets the job done. So why I made the switch? Because I had a
tool as useful as
supervisord and came pre-installed with Centos 7.
systemd as a process supervisor
systemd uses configuration files named ‘unit file’. Below is a unit file for
[Unit] Description="Foo web application" After=network.target [Service] User=foo Group=foo Environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8 ExecStart=/home/foo/bin/start_foo [Install] WantedBy=multi-user.target
After copying this to
/etc/systemd/system/foo.service I can control
$ systemctl status foo $ systemctl stop foo $ systemctl start foo $ systemctl restart foo
One of the key features of
supervisord is restarting the process on a crash.
systemd I can have the same behavior by adding
Restart option can have settings other than
For complete list see
Celery to the equation. I want to control my main service and
Celery both independently and together. For this, I have to create a ‘target’.
Targets are unit files too but useful for grouping and ordering other services.
[Unit] After=network.target Wants=foo_django.service foo_celery.service [Install] WantedBy=multi-user.target
services listed in
Wants starts when target starts, but if one of them fails
it won’t affect the target. So, if
foo_celery.service fails to start, it
will not affect
In order to use my target, I have to change my units like this:
[Unit] Description="Foo web application" After=network.target PartOf=foo.target [Service] User=foo Group=foo Environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8 ExecStart=/home/foo/bin/start_foo [Install] WantedBy=multi-user.target
According to the same manual, a dependency is established between units and
targets listed in the
PartOf and starting or stopping the target will affect
these units. However, this dependency relation is unidirectional, starting or
stopping one of the units will not affect other units dependent on the same
target. So, when I start
foo.target, it will start
foo_celery.service but if I restart
foo won’t be affected.
Finally, I can check dependent services with
list-dependencies. The dot on
the left is green or red according to the service’s status.
$ systemctl list-dependencies foo.target foo.target ● ├─foo_django.service ● └─foo_celery.service
I’m not saying
supervisor is bad or
systemd is superior.
Supervisor is a
reliable tool that I use day to day. Also, it has some features that
has not, like controlling services with a web interface. Nevertheless, if your
only use case is making sure of your processes are running all the time you can
systemd and getting rid of one dependency from your systems.