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 worker
starts the servicesystemctl --user stop worker
stops the servicesystemctl --user restart worker
restarts the workersystemctl --user status worker
shows the service's statussystemctl --user enable worker
starts the service on bootsystemctl --user disable worker
service will not start on bootsystemctl --user daemon-reload
notify 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.