Skip to content

Commit b371964

Browse files
committed
fix(jobs): improve mysql error handling for deadlocks and lock timeouts
1 parent a0ec9f1 commit b371964

1 file changed

Lines changed: 9 additions & 7 deletions

File tree

app/jobs/record_usages.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -321,20 +321,22 @@ async def safe_execute(stmt, params=None, max_retries: int = 2):
321321
# Session auto-closed by context manager, locks released
322322

323323
# Determine error type for retry logic
324-
is_mysql_deadlock = (
325-
hasattr(err, "orig")
326-
and hasattr(err.orig, "args")
327-
and len(err.orig.args) > 0
328-
and err.orig.args[0] == 1213
324+
mysql_errno = (
325+
err.orig.args[0]
326+
if hasattr(err, "orig") and hasattr(err.orig, "args") and len(err.orig.args) > 0
327+
else None
329328
)
329+
# 1213 = deadlock, 1205 = lock wait timeout
330+
is_mysql_retriable = mysql_errno in (1213, 1205)
330331
is_pg_deadlock = hasattr(err, "orig") and hasattr(err.orig, "code") and err.orig.code == "40P01"
331332
is_sqlite_locked = "database is locked" in str(err)
332333

333334
# Retry with exponential backoff if retriable error
334335
if attempt < max_retries - 1:
335-
if is_mysql_deadlock or is_pg_deadlock:
336+
if is_mysql_retriable or is_pg_deadlock:
336337
# Exponential backoff with jitter: 50-75ms, 100-150ms
337-
base_delay = 0.05 * (2**attempt)
338+
# Use longer base delay for lock wait timeouts vs deadlocks
339+
base_delay = 0.1 * (2**attempt) if mysql_errno == 1205 else 0.05 * (2**attempt)
338340
jitter = random.uniform(0, base_delay * 0.5)
339341
await asyncio.sleep(base_delay + jitter)
340342
continue

0 commit comments

Comments
 (0)