Skip to content

Commit 89f32b9

Browse files
committed
perf(tests): skip thread.join in run_server_in_thread teardown
uvicorn polls should_exit every 0.1s in its main_loop and adds another 0.1s sleep in shutdown(), so thread.join() blocks ~200ms per fixture teardown. With 60+ fixture-using tests in test_streamable_http.py, that was ~12s of pure shutdown latency. The thread is a daemon, so signaling exit and moving on is safe — the interpreter reaps it. The socket is still closed by uvicorn's shutdown, releasing the port. Sequential runtime for affected files: 24s → 13s (old multiprocessing baseline was 16s). Parallel (-n 14) runtime unchanged at ~4.5s.
1 parent e9d75da commit 89f32b9

File tree

1 file changed

+6
-1
lines changed

1 file changed

+6
-1
lines changed

tests/test_helpers.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,12 @@ def run_server_in_thread(app: ASGIApp, lifespan: Literal["auto", "on", "off"] =
8383
yield f"http://127.0.0.1:{port}"
8484
finally:
8585
server.should_exit = True
86-
thread.join(timeout=5)
86+
server.force_exit = True
87+
# Don't block on thread.join() — uvicorn polls should_exit every 0.1s and
88+
# its shutdown() adds another 0.1s, totaling ~200ms teardown latency per
89+
# fixture. The thread is a daemon so it will be reaped by the interpreter;
90+
# we just signal exit and move on. The socket is closed by uvicorn's
91+
# shutdown regardless, so the port is released for the next test.
8792
# When uvicorn shuts down with in-flight SSE connections, the server
8893
# cancels request handlers mid-operation. SseServerTransport's internal
8994
# memory streams may not get their `finally` cleanup run before GC,

0 commit comments

Comments
 (0)