Run code in python script on shutdown signal
Question: I have a python script that runs in the background on startup. The starting
method is a entry in a run.sh file which is called with /etc/rc.local. The
exact entry would be "sudo python /home/pi/run/main.py &". The system is a
raspberry pi with wheezy.

The script is running, no problem so far. If a shutdown command is send to the
system (via console "sudo shutdown -h now") I need further the script to not
abort right away but to execute some code first. Thats what I got so far:

    
    
    #!/usr/bin/env python
    
    import atexit
    
    @atexit.register
    def byebye():
        c = "End"
        datei = open("/home/pi/logfile",'a+b')
        datei.write(c + "\n")
        datei.close()
    
    def main():
    
       while True:
         ...do anything...
    
    main()
    

Right now it seems to just exit the main loop on shutdown. Do I need to use a
different way to shutdown the system so the signal is transmitted to my script
or did I maybe not get the usage of the "@atexit" method? Any ideas?

Thanks


Answer: `shutdown` sends the `SIGTERM` signal, which `atexit` does not handle. Nor
will context managers, `finally` blocks, etc.

    
    
    import signal
    
    signal.getsignal(signal.SIGTERM)
    Out[64]: 0 #i.e. nothing
    

Contrast this with, say ctrl-C:

    
    
    signal.getsignal(signal.SIGINT)
    Out[65]: <function signal.default_int_handler> #i.e. something
    

You can register your `byebye` function with `signal` to run instead of doing
nothing (which leads to the interpreter eventually getting killed by the
shell)

    
    
    signal.signal(signal.SIGTERM,byebye)
    

If you do the above you'll need to do two things:

  * change the signature of `byebye` to accept the two arguments that `signal` will pass to it.
  * you should do something like call `sys.exit()` at the end of your `byebye` function to allow python to gracefully close up shop. 

You could alternatively do some combination of `signal` _and_ `atexit`:

    
    
    import sys
    signal.signal(signal.SIGTERM, lambda num, frame: sys.exit(0))
    

Which would drop right in to your current code. This ensures the atomicity of
your cleanup operation (i.e. `byebye` is guaranteed to be the last I/O
operation) at the cost of being a bit clunky.

