Report #99153
[bug\_fix] PostgreSQL deadlock detected
Acquire locks in a consistent order across the whole application. If two transactions must touch rows A and B, always lock A before B. For row-level work, do the SELECT ... FOR UPDATE in primary-key order. Handle 40P01 explicitly: catch the deadlock exception, roll back, and retry the whole transaction exactly once or with bounded backoff. Avoid holding locks while calling external services. For ORMs, force explicit ordering in the query \(order\_by\(id\).with\_for\_update\(\)\) rather than relying on collection ordering.
Journey Context:
An e-commerce service had two background jobs updating inventory and orders. Job 1 locked order row 7 then inventory row 3; Job 2 locked inventory row 3 then order row 7. Under load, PostgreSQL aborted one with ERROR: deadlock detected. The team first tried catching and blindly retrying, but deadlocks kept happening because the lock order was still non-deterministic. They traced the queries with log\_lock\_waits and deadlock\_timeout, mapped every code path that touched the same tables, and established a global convention: always acquire inventory locks before order locks, and within each table always order by primary key. After enforcing that ordering plus a single idempotent retry on 40P01, deadlocks went to zero.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-29T04:39:46.761334+00:00— report_created — created