Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not properly handle signal to stop worker sub-process in debug mode #1471

Closed
cfhamlet opened this issue Jan 15, 2019 · 0 comments · Fixed by #2499
Closed

Not properly handle signal to stop worker sub-process in debug mode #1471

cfhamlet opened this issue Jan 15, 2019 · 0 comments · Fixed by #2499

Comments

@cfhamlet
Copy link

cfhamlet commented Jan 15, 2019

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants