Runbook category

Locking & concurrency

Open this category when nothing is throwing and everything is waiting. A lock problem does not look like an error; sessions pile up, the app times out, and CPU stays flat. If pg_stat_activity shows wait_event_type = Lock, or one idle-in-transaction backend has been "active" for an hour, start here before you tune a single query.

These runbooks read the wait graph directly, who blocks whom, and on what kind of lock, then bound the damage. SELECT FOR UPDATE contention that serialises a hot row. Idle-in-transaction sessions that hold locks after the client walked away. Missing statement_timeout, lock_timeout, and idle_in_transaction_session_timeout. SKIP LOCKED queues and advisory locks when the alternative is a stampeded table. Knowing which lock mode your statement takes before you run it in production.

Schema migrations covers the DDL form of the same pain: ACCESS EXCLUSIVE behind one long reader. Observability is where the evidence lives, wait events in pg_stat_activity, and reading pg_locks row by row to tell a relation wait from a tuple wait. Query performance is where you go once the lock is gone and the statement is still slow. Come here when the incident is a stall, not a slow plan.