Closed Kludex closed 5 months ago
@maxfischer2781 FYI
I think I'm seeing something similar? If I run my FastAPI application with something like uvicorn <module.path:app>
and end it with ^C
I get something like this:
...
^C2024-03-26 18:56:10.932 | INFO | uvicorn.server:shutdown:258 - Shutting down
2024-03-26 18:56:11.033 | INFO | uvicorn.lifespan.on:shutdown:67 - Waiting for application shutdown.
2024-03-26 18:56:13.739 | INFO | uvicorn.lifespan.on:shutdown:76 - Application shutdown complete.
2024-03-26 18:56:13.739 | INFO | uvicorn.server:_serve:92 - Finished server process [72530]
Aborted!
Debugging the same command with VS Code and debugpy
confirms an Exception is being raised:
Exception has occurred: SystemExit
...
File "/Users/proever/Developer/base/path/.venv/lib/python3.10/site-packages/uvicorn/server.py", line 328, in capture_signals
signal.raise_signal(captured_signal)
KeyboardInterrupt:
The above exception was the direct cause of the following exception:
File "/Users/proever/Developer/base/path/.venv/lib/python3.10/site-packages/click/core.py", line 1091, in main
raise Abort() from e
click.exceptions.Abort:
During handling of the above exception, another exception occurred:
File "/Users/proever/Developer/base/path/.venv/lib/python3.10/site-packages/click/core.py", line 1121, in main
sys.exit(1)
File "/Users/proever/Developer/base/path/.venv/lib/python3.10/site-packages/click/core.py", line 1157, in __call__
return self.main(*args, **kwargs)
File "/Users/proever/Developer/base/path/.venv/lib/python3.10/site-packages/uvicorn/__main__.py", line 4, in <module>
uvicorn.main()
File "/Users/proever/.pyenv/versions/3.10.13/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/Users/proever/.pyenv/versions/3.10.13/lib/python3.10/runpy.py", line 196, in _run_module_as_main (Current frame)
return _run_code(code, main_globals, None,
SystemExit: 1
But maybe it's a problem with FastAPI?
Thanks for the ping @Kludex . The timing indeed makes this suspiciously likely to be related to the new signal handling.
I'm not sure how the change itself would lead to that behaviour, though. Is there some cleanup (of subprocesses) happening after Server.serve
completes that would now be skipped by the KeyboardInterrupt
?
I think the reason for this issue is that the capture_signals context in server.py ensure that anything passed to Server.serve runs with the modified signal handlers instead of the default ones. If a child process is created within this context, python's default behavior makes the child processes inherit the parent's signal handlers which in this case is the handle_exit signal handler. Since the child process is now running with a signal handler that does not kill the process on SIGINT or SIGTERM, KeyboardInterrupt is not able to end it. I tested this theory out a bit, and it seems to be the case in my tests. A potential fix is to modify the handle_exit signal handler to do its logic only for the main process. This could be done by comparing the pid. I tested this out as well, and it seems to fix the problem. I could create a pull request if you think it could be a valid solution.
I'm not sure how that would be the cause. Installing the custom signal handlers is something that happened before already. The change was only to restore the original signal handlers on exit.
My bad, forget everything I said. I was using multiprocess fork instead of spawn for the child process and that was messing things up. With spawned child process, I'm not able to reproduce the issue.
Fixed on 0.30.0.
the problem still exist on my side -> Version: 0.30.6
Should I include any additional parameters to ensure child processes are terminated?
uvicorn.run( "__main__:app", host="0.0.0.0", workers=1, reload=False, log_level="info", interface="asgi3", )
Version: 0.28.1:
Version: 0.30.6:
Discussed in https://github.com/encode/uvicorn/discussions/2281