Devsolved
Sep 10, 2023 —
16:00 UTC
MTTR:
24 hours
1 min read
195000 views
Executive Summary
Our primary Postgres cluster suddenly stopped accepting all write operations and forced itself into read-only mode to prevent catastrophic data corruption due to transaction ID exhaustion.
Database Impact: 4 hours of total write downtime. No users could sign up, purchase, or modify data.
The Symptom
Symptom
Every single `INSERT`, `UPDATE`, or `DELETE` query failed instantly with the error: `ERROR: database is not accepting commands to avoid wraparound data loss in database "production"`.
Root Cause Analysis
Root
Cause
PostgreSQL uses a 32-bit integer for Transaction IDs (XIDs), allowing ~2 billion transactions. To reuse IDs safely without older data disappearing (becoming "invisible"), Postgres runs a background process called "autovacuum" to freeze old transaction IDs. A massive, long-running data migration script had been running for 5 days. This long-running transaction blocked autovacuum from freezing any rows. The XID counter eventually hit the 2-billion limit, forcing Postgres into read-only mode to prevent catastrophic data loss.
Resolution
Resolution
We had to SSH into the database instances, forcefully terminate the hanging data migration transaction using `pg_cancel_backend()`, and then run an aggressive manual `VACUUM FREEZE` in single-user mode. This process took 4 hours due to disk I/O constraints.
Preventive Action Items
criticalAdd Datadog alerts for `xid_age` > 1.5 billion@DBA Team
highSet `idle_in_transaction_session_timeout` to 5 minutes to kill hung scripts automatically@DBA Team
|
Discussions
0
Most recent
Embed Incident
Copy the HTML below to embed this postmortem on your company blog, Notion, or internal docs.
Discussions 0