What I want
I have a systemd service that I would like to have stopped before suspend/shutdown, and start up again after resume.
System details
System details below.
$ lsb_release -dc
Description: Ubuntu 20.04.1 LTS
Codename: focal
$ systemd --version
systemd 245 (245.4-4ubuntu3.3)
+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=hybrid
What I have so far
I have two services, myservice-resume.service
and myservice-suspend.service
respectively starting and stopping a python process at suspend and resume. The python script issues commands to an SDK server that controls RGB lighting. When on is passed as an argument (as in ExecStart), the process must be left running in the background to keep issuing commands as part of a loop. When the process catches a SIGINT signal the lighting is switched off and gracefully exits. In this setup, myservice-suspend.service is triggered before suspend and causes stopping of myservice-resume.service
due to conflict.
myservice-resume.service
[Unit]
Description=Start myservice-resume.service after suspend and shutdown
[Service]
Type=simple
ExecStart=/path/to/python3 /path/to/script.py on
myservice-suspend.service
[Unit]
Description=Stop myservice-resume.service before suspend and shutdown
Before=suspend.target shutdown.target
Conflicts=myservice-resume.service
[Service]
Type=oneshot
ExecStart=/bin/true
[Install]
WantedBy=suspend.target shutdown.target
In this setup, I start the service (and lighting) using systemctl start myservice-resume.service
and successfully turn off lighting using systemctl start myservice-suspend.service
, systemctl stop myservice-resume.service
, or by doing a system suspend using systemctl suspend
. I'd like to have the first service, myservice-resume.service
, automatically start again on system resume. I'd imagine that this would involve adding some clever After/Before/WantedBy targets in the [Unit] and [Install] sections, but I can't determine an appropriate way to set this up.
Research/What I've tried
A related post (Systemd: stop service before suspend, restart after resume) hinted that I could configure a service to run after resume from suspend by adding After=suspend.target
to the Unit section of myservice-resume.service
. I've tried this, but the systemctl log shows that the unit was not started again on resume.
This post (Writing systemd unit file for suspend/resume) points the OP to the systemd man pages to come up with a solution (and clarifies the purpose of After/WantedBy), but I couldn't find a solution here either.
Best Answer
The need for an
After=
orBefore=
can finally be seen in examples from archlinux (a remarkable source of help as usual). Based on that link, there are two solutions to running a command on suspend and resume.One method is to use two units, say
mysyssuspend
andmysysresume
. The following examples just run thedate
command to syslog so we can see when they get activated:/etc/systemd/system/mysyssuspend.service
/etc/systemd/system/mysysresume.service
As usual, do a
systemctl daemon-reload
andsystemctl enable mysyssuspend mysysresume
after creating the unit files.The first unit has a
Before
dependency on the suspend target and gets run when the computer enters suspend. The second unit similarly has anAfter
dependency, and gets run on resuming.The other method puts all the commands in a single unit:
/etc/systemd/system/mysuspendresume.service
This works with
StopWhenUnneeded=yes
, so the service is stopped when no active service requires it. The sleep target also hasStopWhenUnneeded
, so when it is finished it will runExecStop
of our unit. TheRemainAfterExit
is needed so that our unit is still seen as active, even afterExecStart
has finished.I tested both of these methods on Ubuntu 18.04.5 with systemd version 237 and they both seem to work correctly.
Rather than trying to merge your requirement into the above working mechanisms, it is probably more pragmatic to use one of them to stop/start an independent unit. For example, use the second method and add a
mylongrun
service:/etc/systemd/system/mysuspendresume.service
/etc/systemd/system/mylongrun.service
Testing this by starting
mylongrun
then closing the lid gives the following journalctl entries:We can see the long running stop command (
sleep 10
) completed correctly. On resume, the long run command is started again: