From e1fec6b3e0f0c7d3406a6b519642f920d6ae07af Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Tue, 12 May 2026 10:28:49 +0200 Subject: [PATCH] test: bound `serve_in_thread` teardown to prevent CI hangs The session-scoped `http_server` fixture's teardown called `thread.join()` without a timeout. When uvicorn occasionally ignored `should_exit`, the join blocked until pytest-timeout killed the run after 30 minutes. Bound the join, escalate to `force_exit`, and mark the worker thread as a daemon. --- tests/unit/server.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/unit/server.py b/tests/unit/server.py index 69de104149..9ca7544014 100644 --- a/tests/unit/server.py +++ b/tests/unit/server.py @@ -541,7 +541,7 @@ def run(self, sockets: list[socket] | None = None) -> None: def serve_in_thread(server: TestServer) -> Iterator[TestServer]: """Run a server in a background thread and yield it.""" - thread = threading.Thread(target=server.run) + thread = threading.Thread(target=server.run, daemon=True) thread.start() try: while not server.started: @@ -549,4 +549,9 @@ def serve_in_thread(server: TestServer) -> Iterator[TestServer]: yield server finally: server.should_exit = True - thread.join() + thread.join(timeout=10) + if thread.is_alive(): + # Uvicorn occasionally ignores should_exit; force_exit aborts the + # asyncio loop so teardown cannot hang the suite indefinitely. + server.force_exit = True + thread.join(timeout=5)