Member-only story
Two Requests, One Deadlock: Postgres Locks With a Real Example
179 of 500 transfers failed with 40P01. Locking rows in the same order took that to zero
I ran 500 money transfers between 10 accounts, 20 at a time. 179 of them failed with deadlock detected, and the run took 93 seconds.
The code looked fine. Each transfer was one transaction with two UPDATEs. The problem was only the order the rows were locked in.
I will be sharing how I reproduced the deadlock with two requests, how to read the Postgres log, and the two fixes: lock ordering, and a retry on error 40P01. Everything was run on Postgres 16 in Docker with Node 20 and pg.
This article expects you to have minimum knowledge of SQL transactions, but nothing is really complicated here.
How it happens
An UPDATE takes a row lock and keeps it until the transaction ends. Any other transaction that wants to update the same…









