-
-
Notifications
You must be signed in to change notification settings - Fork 756
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
Suppress side-effects of signal propagation #2317
Suppress side-effects of signal propagation #2317
Conversation
I can't reproduce it. How did you? |
@Kludex Sorry, I forgot to add one detail. To reproduce the Windows behaviour on UNIX, one must patch how the subprocesses are killed (SIGINT on Windows vs SIGTERM on UNIX). In uvicorn/uvicorn/supervisors/basereload.py Lines 92 to 93 in 0efd383
to sending SIGINT explicitly: else: # pragma: py-win32
self.process._popen._send_signal(signal.SIGINT) Afterwards, run the example mentioned above. Saving any file should trigger a reload and finishing the subprocess triggers a traceback as below:
Note This patch is only for testing the Windows behaviour on UNIX and not part of the actual fix. |
if config.uds and os.path.exists(config.uds): | ||
os.remove(config.uds) # pragma: py-win32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move this to Server.shutdown
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems sensible. I'll give it a try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Sorry for the delay on follow up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've experimented with this but see no way to make it work well. The socket can be owned by either main:run
(for reload and workers) or Server
(otherwise). When moving cleanup to Server.shutdown
I would have to duplicate it inside the reload and worker code as well.
So main:run
seems adequate for cleanup, since it owns the Server
as well.
Not to distract your quality work, but I just wanted to add my experience. I've had the following monkey patch in if is_dev:
get = asyncio.Queue.get
async def new_get(self):
try:
return await get(self)
except asyncio.exceptions.CancelledError:
pass
asyncio.Queue.get = new_get But it stopped working after upgradeing to INFO: Shutting down
INFO: Finished server process [98267]
ERROR: Traceback (most recent call last):
File ".pyenv/versions/3.10.10/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "uvloop/loop.pyx", line 1511, in uvloop.loop.Loop.run_until_complete
File "uvloop/loop.pyx", line 1504, in uvloop.loop.Loop.run_until_complete
File "uvloop/loop.pyx", line 1377, in uvloop.loop.Loop.run_forever
File "uvloop/loop.pyx", line 555, in uvloop.loop.Loop._run
File "uvloop/loop.pyx", line 474, in uvloop.loop.Loop._on_idle
File "uvloop/cbhandles.pyx", line 83, in uvloop.loop.Handle._run
File "uvloop/cbhandles.pyx", line 63, in uvloop.loop.Handle._run
File ".venv/lib/python3.10/site-packages/uvicorn/server.py", line 68, in serve
with self.capture_signals():
File ".pyenv/versions/3.10.10/lib/python3.10/contextlib.py", line 142, in __exit__
next(self.gen)
File ".venv/lib/python3.10/site-packages/uvicorn/server.py", line 328, in capture_signals
signal.raise_signal(captured_signal)
KeyboardInterrupt
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File ".venv/lib/python3.10/site-packages/starlette/routing.py", line 741, in lifespan
await receive()
File ".venv/lib/python3.10/site-packages/uvicorn/lifespan/on.py", line 137, in receive
return await self.receive_queue.get()
File ".pyenv/versions/3.10.10/lib/python3.10/asyncio/queues.py", line 159, in get
await getter
asyncio.exceptions.CancelledError
Process SpawnProcess-1:
Traceback (most recent call last):
File ".pyenv/versions/3.10.10/lib/python3.10/multiprocessing/process.py", line 314, in _bootstrap
self.run()
File ".pyenv/versions/3.10.10/lib/python3.10/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File ".venv/lib/python3.10/site-packages/uvicorn/_subprocess.py", line 78, in subprocess_started
target(sockets=sockets)
File ".venv/lib/python3.10/site-packages/uvicorn/server.py", line 65, in run
return asyncio.run(self.serve(sockets=sockets))
File ".pyenv/versions/3.10.10/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "uvloop/loop.pyx", line 1511, in uvloop.loop.Loop.run_until_complete
File "uvloop/loop.pyx", line 1504, in uvloop.loop.Loop.run_until_complete
File "uvloop/loop.pyx", line 1377, in uvloop.loop.Loop.run_forever
File "uvloop/loop.pyx", line 555, in uvloop.loop.Loop._run
File "uvloop/loop.pyx", line 474, in uvloop.loop.Loop._on_idle
File "uvloop/cbhandles.pyx", line 83, in uvloop.loop.Handle._run
File "uvloop/cbhandles.pyx", line 63, in uvloop.loop.Handle._run
File ".venv/lib/python3.10/site-packages/uvicorn/server.py", line 68, in serve
with self.capture_signals():
File ".pyenv/versions/3.10.10/lib/python3.10/contextlib.py", line 142, in __exit__
next(self.gen)
File ".venv/lib/python3.10/site-packages/uvicorn/server.py", line 328, in capture_signals
signal.raise_signal(captured_signal)
KeyboardInterrupt
INFO: Stopping reloader process [98264] |
@kenn This PR will remove the However, the first traceback does not seem to include your |
Thanks! I know this is a dirty hack, but it works for a single purpose as expected — suppress the verbose tracebacks upon ctrl-C while preserving its original functionality 100%. |
Thanks @maxfischer2781 :) |
This commit will update/upgrade Uvicorn [from 0.28.1 to 0.34.0](encode/uvicorn@0.28.1...0.34.0). There were some notable (but undocumented) updates to signal handling introduced in Uvicorn 0.29. The updates may result in child processes that do not shut down after the Uvicorn server gracefully shuts down ([encode/uvicorn#1600](encode/uvicorn#1600), [encode/uvicorn#2281](encode/uvicorn#2281), [encode/uvicorn#2289](encode/uvicorn#2289), [encode/uvicorn#2317](encode/uvicorn#2317)). For this reason, it may be helpful to check servers for orphaned child processes. See the GitHub references above for further info. As noted in commit 3ab51b6, Uvicorn workers were deprecated in 0.30.0. The workers are now available at `inboard.gunicorn_workers`. Other updates include an overhaul of the Uvicorn multiprocess manager (`uvicorn.supervisors.process.Multiprocess`, [encode/uvicorn#2183](encode/uvicorn#2183)) and small updates to the `forwarded_allow_ips`/`--forwarded-allow-ips` config setting.
This commit will update/upgrade Uvicorn [from 0.28.1 to 0.34.0](encode/uvicorn@0.28.1...0.34.0). There were some notable (but undocumented) updates to signal handling introduced in Uvicorn 0.29. The updates may result in child processes that do not shut down after the Uvicorn server gracefully shuts down ([encode/uvicorn#1600](encode/uvicorn#1600), [encode/uvicorn#2281](encode/uvicorn#2281), [encode/uvicorn#2289](encode/uvicorn#2289), [encode/uvicorn#2317](encode/uvicorn#2317)). For this reason, it may be helpful to check servers for orphaned child processes. See the GitHub references above for further info. As noted in commit 35d8d86, Uvicorn workers were deprecated in 0.30.0. The workers are now available at `inboard.gunicorn_workers`. Other updates include an overhaul of the Uvicorn multiprocess manager (`uvicorn.supervisors.process.Multiprocess`, [encode/uvicorn#2183](encode/uvicorn#2183)) and small updates to the `forwarded_allow_ips`/`--forwarded-allow-ips` config setting.
Summary
This PR suppresses noise and dirt from signal propagation introduced in #1600.
multiprocessing.process
on any exception. Since the shutdown exception is expected, subprocesses spawned for workers/reload simply discard it.uvicorn.run
exits. This would previously be skipped on forced shutdown.Note: I was not able to reproduce #2281 / #2289 so I do not know if they are fixed by this. However, this fixes the various reports on those discussions/issues about tracebacks.
I do not have access to a Windows machine for testing so had to emulate it. It would be nice if someone can confirm that this works on Windows.A minimal repro is the programrun via
@johanboekhoven kindly tested this on Windows.
Checklist