Systemd user units
Systemd is mainly used to manage services on modern linux distributions, but it also allows non-root users to manage services running under their own account. This makes systemd a great alternative to services like supervisord as it is able to detect crashes and automatically restarts the service.
Configuring a user unit
The directory structure that holds unit files is similar to the system-wide configuration, but is located in a user's home directory.
If this directory does not exist, you can create it with the command below:
mkdir -p ~/.config/systemd/user
Navigate into this folder:
cd ~/.config/systemd/user
Here you can add a new file where the filename will also serve as the service name. For systemd to recognize it as a unit, the file must have a .service extension.
For example, if you want systemd to manage a Laravel PHP queue worker, create a file named worker.service using your preferred text editor (nano, vim, etc.), and add the following configuration:
[Unit]
Description=Laravel PHP queue worker
[Service]
ExecStart=/usr/bin/env php /path/to/my/project/artisan queue:work --sleep=3 --tries=3
[Install]
WantedBy=default.target
Notify systemd of the newly created service:
systemctl --user daemon-reload
Managing a user unit
Now you can manage this service with systemd:
systemctl --user start workerstarts the servicesystemctl --user stop workerstops the servicesystemctl --user restart workerrestarts the workersystemctl --user status workershows the service's statussystemctl --user enable workerstarts the service on bootsystemctl --user disable workerservice will not start on bootsystemctl --user daemon-reloadnotify systemd to reload changes
Editing the .service file
When making changes to the .service file, don't forget to run systemctl --user daemon-reload to make systemd aware of your changes before restarting the service.
Starting user services at boot
By default, systemd starts enabled user units when the user logs in, and stops them once the user has logged out. This is great for desktop pcs where a user wants to run things while he's using the computer. On servers, however, we may want to run those units all the time. To ensure that services don’t stop when a user logs out, and automatically starts again on boot, lingering must be enabled for that user.
We enable lingering by default for all SOCK users, so the only thing left to do is enabling your service:
systemctl --user enable worker
Viewing logs
Everything our PHP script writes to stdout and stderr will be recorded by journald.
We can view the logs for this specific service:
journalctl -u worker
Automatically restarting on failure
Let's be honest: things go wrong. When our worker crashes we want to make sure it's started again.
Fortunately, we can configure systemd to restart on failure:
Add the following to the [Service] section of the unit file:
RestartSec=10s
Restart=on-failure
This makes systemd restart the service 10 seconds after it has stopped with a non-zero exit code. If the process exited cleanly, systemd considers the work as done and won't restart the service until you manually start it later.