From e4db1a211c2dbe6a783bf7d67ef4ca798c5f5ed6 Mon Sep 17 00:00:00 2001 From: Dotta Date: Sat, 6 Jun 2026 14:46:27 +0000 Subject: [PATCH] test: retry watchdog cleanup deadlocks Co-Authored-By: Paperclip --- ...artbeat-active-run-output-watchdog.test.ts | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/server/src/__tests__/heartbeat-active-run-output-watchdog.test.ts b/server/src/__tests__/heartbeat-active-run-output-watchdog.test.ts index a5b3abb510f..452bf6eecdf 100644 --- a/server/src/__tests__/heartbeat-active-run-output-watchdog.test.ts +++ b/server/src/__tests__/heartbeat-active-run-output-watchdog.test.ts @@ -73,6 +73,31 @@ if (!embeddedPostgresSupport.supported) { ); } +function errorHasPostgresCode(error: unknown, code: string): boolean { + let current: unknown = error; + for (let depth = 0; depth < 4; depth += 1) { + if (!current || typeof current !== "object") return false; + const record = current as { code?: unknown; cause?: unknown }; + if (record.code === code) return true; + current = record.cause; + } + return false; +} + +async function truncateCompaniesWithDeadlockRetry(db: ReturnType) { + for (let attempt = 0; attempt < 5; attempt += 1) { + try { + await db.execute(sql.raw(`TRUNCATE TABLE "companies" CASCADE`)); + return; + } catch (error) { + if (!errorHasPostgresCode(error, "40P01") || attempt === 4) { + throw error; + } + await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1))); + } + } +} + describeEmbeddedPostgres("active-run output watchdog", () => { let tempDb: Awaited> | null = null; let db: ReturnType; @@ -91,7 +116,7 @@ describeEmbeddedPostgres("active-run output watchdog", () => { if (activeRuns.length === 0) break; await new Promise((resolve) => setTimeout(resolve, 25)); } - await db.execute(sql.raw(`TRUNCATE TABLE "companies" CASCADE`)); + await truncateCompaniesWithDeadlockRetry(db); }); afterAll(async () => {