10

I want a simple python script to run in background, therefore I configured daemon test.service in /etc/systemd/system/.

[Unit]
Description=Test service
After=multi-user.target

[Service]
Type=simple
ExecStart=/usr/bin/python /home/pi/daemon.py
Restart=on-abort

[Install]
WantedBy=multi-user.target

My executing script daemon.py toogles a LED controlled by a button.

#!/usr/bin/python

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)

# Configure button pin
GPIO.setup(14, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# Configure LED pin
GPIO.setup(18, GPIO.OUT)

def button1(channel):
    print "Toogle LED!"
    GPIO.output(18, not GPIO.input(18))

GPIO.add_event_detect(14, GPIO.FALLING, callback=button1, bouncetime=300)

try:
    while True:
        pass

finally:
    print "cleanup() GPIOs"
    GPIO.cleanup()

Now, I can start my script as a service with systemctl start test.service and stop it the same way. But for a clean script, I want to execute GPIO.cleanup() before the script is closed by systemctl stop test.service. How can I achieve that? The finally doesn't seem to work in this case...

Secondly, all the print messages like "Toogle LED!" cannot be seen when I call systemctl status test.service. Is the output written to another file somewhere else?

Thank you for your help in advance!

2 Answers 2

10

Now, I can start my script as a service with systemctl start test.service and stop it the same way. But for a clean script, I want to execute GPIO.cleanup() before the script is closed by systemctl stop test.service. How can I achieve that? The finally doesn't seem to work in this case...

By default, systemd sends a SIGTERM, then SIGKILL to your service unless you've specified more complex logic. SIGTERM doesn't raise an exception in Python, so your finally block probably doesn't get run.

Try adding:

KillSignal=SIGINT

Below [Service] to tell systemd to send a SIGINT, which is translated as a KeyboardInterrupt exception by Python. This should then run your graceful exit logic.

Secondly, all the print messages like "Toogle LED!" cannot be seen when I call systemctl status test.service. Is the output written to another file somewhere else?

Yes, you should use:

journalctl -u test.service

This will read the systemd journal logs for your service. status just gives you a brief summary of whether your service is functioning; it's not the full log.

5
  • Thanks for your answer! It works right in the way it should. But by the way: Is that the preferred way to make a script run in background or is it better to use a python daemon class like link. What's the difference in both approaches?
    – EarlyEarl
    Commented Jan 14, 2018 at 14:47
  • 1
    If you are always going to run it via systemd you don't have to do the fork/setsid thing yourself (which is what daemonization is). However, you may want to look into signal handling so you can do a clean exit for SIGTERM and other things.
    – goldilocks
    Commented Jan 14, 2018 at 14:51
  • Honestly, I think a systemd service is far superior, @EarlyEarl. Systemd handles a lot of the complexity of running a service like logging, dependency management, consistent command line interface, etc. That code (from 2007) was written before systemd existed, and won't cover all of the features that systemd does. I'd always suggest not reinventing the wheel in this situation — systemd does the job well, so there's no need to over-complicate things.
    – Aurora0001
    Commented Jan 14, 2018 at 14:52
  • 1
    Perfect. Then I will stay with this solution. Thank you!
    – EarlyEarl
    Commented Jan 14, 2018 at 15:15
  • You can capture SIGTERM, see stackoverflow.com/questions/18499497/…
    – matabares
    Commented Aug 6, 2020 at 10:27
3

You can also do it using the signal native Python package:

def exit_gracefully(signum, frame):
    logging.info('Exited')

signal.signal(signal.SIGTERM, exit_gracefully)
1
  • I think there's an exit() missing in exit_gracefully(signum, frame)
    – monok
    Commented May 2, 2020 at 15:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.