I have my python script used as a linux service. It is started by start-stop-daemon from /etc/init.d/myservice script. Because my program uses GPIO, I was thinking how to call GPIO.cleanup() when I stop my service with sudo service myservice stop command.
The solution I've found is to register signals handlers. It looks like:
You may find great explanation of signals here, but what you need to know is that SIGTERM is sent for example when you simply kill your program with kill command (without -9) and SIGINT is a result of pressing Ctrl+C. The handler is called with two arguments: the signal number and the current stack frame (but it doesn't matter in this example - you only have to define them as arguments to avoid the error "TypeError: handle_exit() takes no arguments (2 given)")
If you don't know how to create script starting your python app when system starts up, you should read this tutorial: http://blog.scphillips.com/posts/2013/07/getting-a-python-script-to-run-in-the-background-as-a-service-on-boot/
To make this tutorial's code work with your signal handlers you should change the following line:
start-stop-daemon --stop --pidfile $PIDFILE --retry 10
to
start-stop-daemon --stop --pidfile $PIDFILE --retry TERM/30/KILL/5 --oknodo --user $DAEMON_USER
This will send TERM signal when you type sudo service myservice stop, and because of registered handlers, your app will exit nicely.
This is a full code of my script placed in /etc/init.d/
The solution I've found is to register signals handlers. It looks like:
import signal handle_exit(signal_number,stack): GPIO.cleanup() exit() signal.signal(signal.SIGTERM, handle_exit) signal.signal(signal.SIGINT, handle_exit)
You may find great explanation of signals here, but what you need to know is that SIGTERM is sent for example when you simply kill your program with kill command (without -9) and SIGINT is a result of pressing Ctrl+C. The handler is called with two arguments: the signal number and the current stack frame (but it doesn't matter in this example - you only have to define them as arguments to avoid the error "TypeError: handle_exit() takes no arguments (2 given)")
If you don't know how to create script starting your python app when system starts up, you should read this tutorial: http://blog.scphillips.com/posts/2013/07/getting-a-python-script-to-run-in-the-background-as-a-service-on-boot/
To make this tutorial's code work with your signal handlers you should change the following line:
start-stop-daemon --stop --pidfile $PIDFILE --retry 10
to
start-stop-daemon --stop --pidfile $PIDFILE --retry TERM/30/KILL/5 --oknodo --user $DAEMON_USER
This will send TERM signal when you type sudo service myservice stop, and because of registered handlers, your app will exit nicely.
This is a full code of my script placed in /etc/init.d/
#!/bin/sh ### BEGIN INIT INFO # Provides: startgate # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Put a short description of the service here # Description: Put a long description of the service here ### END INIT INFO # Change the next 3 lines to suit where you install your script and what you want to call it DIR=/home/pi/bmxstartgate13-02-2016/bmxstartgate DAEMON=$DIR/startgate.py DAEMON_NAME=startgate # Add any command line options for your daemon here DAEMON_OPTS="" # This next line determines what user the script runs as. # Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python. DAEMON_USER=pi # The process ID of the script when it runs is stored here: PIDFILE=/var/run/$DAEMON_NAME.pid . /lib/lsb/init-functions do_start () { log_daemon_msg "Starting system $DAEMON_NAME daemon" start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS log_end_msg $? } do_stop () { log_daemon_msg "Stopping system $DAEMON_NAME daemon" #start-stop-daemon --stop --pidfile $PIDFILE --retry 10 start-stop-daemon --stop --pidfile $PIDFILE --retry TERM/30/KILL/5 --oknodo --user $DAEMON_USER log_end_msg $? } case "$1" in start|stop) do_${1} ;; restart|reload|force-reload) do_stop do_start ;; status) status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $? ;; *) echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}" exit 1 ;; esac exit 0
I've found also another solution with using atexit (it is mentioned here in comments) but for me it worked only on ctrl+c.
Solution I've described in this post is based on this topic: https://www.raspberrypi.org/forums/viewtopic.php?t=63051
Feel free to ask if you have any questions :)
Solution I've described in this post is based on this topic: https://www.raspberrypi.org/forums/viewtopic.php?t=63051
Feel free to ask if you have any questions :)
Brak komentarzy:
Prześlij komentarz