sanic
sanic copied to clipboard
Not properly handle signal to stop worker sub-process in debug mode
Describe the bug
In the debug mode, if you do not change your source code to trigger auto reload, the stop signals(SIGTERM, SIGINT) send to the main process will not work properly to stop the worker sub-process. As the following code, run it and stop(Ctrl-C), the on_shutdown
method will not be called.
# v18.12.0
from sanic import Sanic
app = Sanic(__name__)
@app.listener('after_server_stop')
def on_shutdown(app, loop):
print('I am done!')
app.run(debug=True)
I think the problem maybe caused by the following code in reloader_helpers.py
:
def watchdog(sleep_interval):
mtimes = {}
worker_process = restart_with_reloader()
signal.signal(
signal.SIGTERM, lambda *args: kill_program_completly(worker_process)
)
signal.signal(
signal.SIGINT, lambda *args: kill_program_completly(worker_process)
)
Because of creating worker_process before register signal hander(kill_program_completly
), the woker_process still use the default signal handler and do not kill sub-process woker.
The following snippet is a immature solution, just for reference:
def kill_program_completly(proc):
if not proc:
kill_process_children(os.getpid())
os._exit(0)
proc = proc.pop()
kill_process_children(proc.pid)
proc.terminate()
os._exit(0)
def watchdog(sleep_interval):
mtimes = {}
worker_process = []
signal.signal(
signal.SIGTERM, lambda *args: kill_program_completly(worker_process)
)
signal.signal(
signal.SIGINT, lambda *args: kill_program_completly(worker_process)
)
worker_process.append(restart_with_reloader())
while True:
for filename in _iter_module_files():
try:
mtime = os.stat(filename).st_mtime
except OSError:
continue
old_time = mtimes.get(filename)
if old_time is None:
mtimes[filename] = mtime
continue
elif mtime > old_time:
wp = worker_process.pop()
kill_process_children(wp.pid)
wp.terminate()
worker_process.append(restart_with_reloader())
mtimes[filename] = mtime
break
sleep(sleep_interval)