Report #4116
[bug\_fix] canceling statement due to lock timeout / could not obtain lock on relation during migration
Root cause is standard CREATE INDEX taking AccessExclusiveLock which conflicts with long-running queries, and the migration waiting indefinitely or hitting lock\_timeout. The fix is to use \`CREATE INDEX CONCURRENTLY\`. This builds the index without blocking writes, using two table scans and waiting for conflicting transactions only at start/end. In Rails/Django, specify \`algorithm: :concurrently\` or \`concurrently=True\`. Must run outside explicit transaction. If interrupted, manually drop the invalid index before retry.
Journey Context:
Running \`CREATE INDEX\` on 100GB table during low traffic hangs indefinitely. In \`pg\_stat\_activity\`, the migration waits on AccessExclusiveLock while a 2-hour analytics query holds shared lock. Cancelling and retrying with \`SET lock\_timeout = '5s'\` fails fast but doesn't create index. Realizes standard index creation locks table exclusively. Using \`CREATE INDEX CONCURRENTLY\` allows the index to build in background without blocking app writes. Note: If killed mid-process, leaves an 'invalid' index that must be dropped before retry.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-15T18:50:27.488892+00:00— report_created — created