Skip to content

Commit 7e091ba

Browse files
committed
fix: bound uvicorn graceful shutdown so thread.join doesn't abandon it mid-drain
Without timeout_graceful_shutdown, uvicorn's shutdown() waits indefinitely for open connections to close. The SSE reconnection tests in test_streamable_http.py can leave streams open at fixture teardown, so the 5s thread.join times out and abandons the thread mid-shutdown. On Windows Proactor, the abandoned connection transports still have pending Overlapped Recv operations when the event loop is torn down. GC later finds them during an unrelated test, surfacing as PytestUnraisableExceptionWarning. Previously hidden by subprocess isolation. timeout_graceful_shutdown=1 gives uvicorn a bounded window to drain connections, then cancels remaining tasks via asyncio — transports unwind through CancelledError instead of being abandoned.
1 parent 36991d8 commit 7e091ba

File tree

1 file changed

+6
-0
lines changed

1 file changed

+6
-0
lines changed

tests/test_helpers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ def run_uvicorn_in_thread(app: Any, **config_kwargs: Any) -> Generator[str, None
4747
# which Python 3.14 deprecates. Under filterwarnings=error this crashes
4848
# the server thread silently. Starlette is asgi3; skip the autodetect.
4949
config_kwargs.setdefault("interface", "asgi3")
50+
# shutdown() waits indefinitely for open connections to drain. SSE tests
51+
# may leave streams open at teardown, so without a bound the join below
52+
# times out and abandons the thread mid-shutdown — on Windows the
53+
# Proactor's Overlapped Recv ops get GC'd pending. This bounds the wait,
54+
# then cancels remaining tasks via asyncio so transports unwind cleanly.
55+
config_kwargs.setdefault("timeout_graceful_shutdown", 1)
5056
server = uvicorn.Server(config=uvicorn.Config(app=app, **config_kwargs))
5157

5258
thread = threading.Thread(target=server.run, kwargs={"sockets": [sock]}, daemon=True)

0 commit comments

Comments
 (0)