From a0a8f72caa9de1681f2211e976d1f36cc04aaf74 Mon Sep 17 00:00:00 2001 From: oabrivard Date: Thu, 26 Mar 2026 11:17:09 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20don't=20join=20Drop=20cleanup=20thread?= =?UTF-8?q?=20=E2=80=94=20prevents=20deadlock=20in=20tokio=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Drop impl spawned a thread with a new tokio runtime and called .join(), which blocked the test thread. The spawned thread's block_on deadlocked when pool.close() tried to communicate with connections owned by the outer tokio runtime. Removing .join() makes cleanup fire-and-forget, avoiding the deadlock. Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/tests/common/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/tests/common/mod.rs b/backend/tests/common/mod.rs index 40ebcb4..2cb4f1c 100644 --- a/backend/tests/common/mod.rs +++ b/backend/tests/common/mod.rs @@ -475,8 +475,9 @@ impl TestApp { impl Drop for TestApp { fn drop(&mut self) { - // Best-effort synchronous cleanup. The `cleanup()` async method is - // preferred, but this catches cases where it wasn't called. + // Fire-and-forget cleanup. Don't .join() — that deadlocks when + // running inside a tokio runtime (the spawned thread's block_on + // conflicts with the existing runtime's connection pool). let admin_pool = self.admin_pool.clone(); let db_name = self.db_name.clone(); let test_pool = self.pool.clone(); @@ -502,8 +503,7 @@ impl Drop for TestApp { .execute(format!("DROP DATABASE IF EXISTS \"{}\"", db_name).as_str()) .await; }); - }) - .join() - .ok(); + }); + // Don't join — let the cleanup thread run independently } }