From 132b15b4e9d2b063ccc92c93450a676404ca411e Mon Sep 17 00:00:00 2001 From: Subhransu De Date: Sun, 11 Oct 2026 12:00:50 +0530 Subject: [PATCH] Wait for aiosqlite worker threads after unreachable-database tests A failed aiosqlite connect queues its worker-thread shutdown without waiting for it (omnilib/aiosqlite#394). When the test's event loop closed first, the thread raised "Event loop is closed", and pytest reported it as an unhandled thread exception in the next test. This flaked test (3.13) on main after #249. Join the worker threads in the unreachable_settings fixture teardown, off the event loop, so the loop is still alive when the thread finishes. --- tests/unit/test_health.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_health.py b/tests/unit/test_health.py index 1b3b490..e3a0215 100644 --- a/tests/unit/test_health.py +++ b/tests/unit/test_health.py @@ -1,3 +1,7 @@ +import threading +from collections.abc import AsyncGenerator + +import anyio import httpx import pytest from asgi_lifespan import LifespanManager @@ -13,9 +17,19 @@ pytestmark = pytest.mark.unit +def _join_aiosqlite_workers() -> None: + for thread in threading.enumerate(): + if thread.name.endswith("(_connection_worker_thread)"): + thread.join(timeout=5) + + @pytest.fixture -def unreachable_settings() -> Settings: - return build_settings(database_url=UNREACHABLE_DATABASE_URL) +async def unreachable_settings() -> AsyncGenerator[Settings]: + yield build_settings(database_url=UNREACHABLE_DATABASE_URL) + # A failed aiosqlite connect stops its worker thread without waiting for it + # (omnilib/aiosqlite#394). If this test's event loop closes first, the thread + # raises "Event loop is closed" and pytest blames whichever test runs next. + await anyio.to_thread.run_sync(_join_aiosqlite_workers) async def test_health_reports_the_application_is_up() -> None: