Stopping Python program from Supervisor
I was quite puzzled recently by a following problem. I needed to run a Python program that had an infinite loop: every N seconds, the script would perform a task. In order to ensure that the script would be restarted automatically if it failed, I was using Supervisor.
As the program was running in a virtual environment, Supervisor would not call directly it, but rather a Bash script, that would prepare the virtual environment, and then start the program.
It appeared, however, that supervisorctl stop all
or service supervisor stop
would not actually stop the Python program—it would continue to run unattended. And, naturally, if I would start Supervisor, it would pop up another instance of the program.
After scratching my head a bit, I found that the issue was the intermediary Bash script. When receiving SIGTERM signal, it would simply stop, while the program would continue to run.
Here's the correct way to do it. First, the program itself:
#!/usr/bin/env python
import signal
import time
if __name__ == '__main__':
should_run = True
def stop(_, _2):
print("Should stop.", flush=True)
global should_run
should_run = False
signal.signal(signal.SIGTERM, stop)
while should_run:
print("Still running.", flush=True)
time.sleep(5)
The Bash script:
#!/bin/bash
source .venv/bin/activate
term() {
kill -TERM "$child"
}
trap term SIGTERM
./example.py &
child=$!
wait "$child"
Note that to keep them simple, those pieces of code handle only the SIGTERM signal. This means that if one runs the Bash script from terminal, Ctrl+C will stop only the Bash script, while Python program will still go on.