Cases3 cases
1 to 3 of 3
IL-0313Decagon voice requests stalled for exactly 300 seconds behind self-managed PgBouncer and exhausted the SQLAlchemy poolDecagon2026- Symptoms
During the first production canary of Decagon's move from GCP's managed connection pooler to self-managed PgBouncer, a small number of voice requests stalled mid-conversation and timed out after exactly 300 seconds. Other requests failed much earlier because the SQLAlchemy connection pool was exhausted.
- Trigger
The move from GCP's managed connection pooler to self-managed PgBouncer enabled a different TLS path between PgBouncer and Postgres, which supplied the last of three conditions needed to expose the bug.
- Root cause
- Component
- Contributing factor
- Detection
Sentry errors ("SSL connection has been closed unexpectedly") and SQLAlchemy connection-pool timeouts during the production canary, followed by a comparison of application spans with Postgres query timings.
- Remediation
- Shortened the application name parameter so the ParameterStatus packet stayed below PgBouncer's small-packet parsing threshold
- Action items
- Fix PgBouncer upstream so it checks SSL_pending() before going back to wait on epoll()
- Lessons
Decagon's lesson is that an infrastructure migration does not only change one's own systems but can also expose latent bugs elsewhere in the stack: the move to self-managed PgBouncer supplied the last condition for a long-standing edge case involving SQLAlchemy, PgBouncer, OpenSSL and the PostgreSQL wire protocol.
IL-0312Gadget's main Postgres did not start again after a restart to raise max_connections, and the platform went downGadget2024- Symptoms
At 11:25 AM EST on 13 December 2024, Gadget restarted its main PostgreSQL server in place to raise max_connections. Postgres shut down but did not start again, and every request to Gadget applications failed, including frontend requests, GraphQL API requests, webhook processing and syncs.
- Trigger
An emergency in-place restart of the main Postgres server at 11:25 AM EST, decided at 11:00 AM, to raise max_connections, which Postgres cannot change without a full restart.
- Root cause
- Component
- Contributing factor
- Detection
The team carrying out the planned restart saw at 11:26 AM EST that Postgres had shut down and did not start again.
- Remediation
- Restarted the database server with a hardware reset, which cleared the fragmented memory so Postgres could start
- Provisioned almost 4x the compute after the autoscalers had scaled it down during the outage
- Action items
- Use only the replica-failover approach for disruptive database operations such as restarts
- Run a more aggressive capacity planning process before Black Friday / Cyber Monday, preparing for a 6x increase in load and proving it with load tests well in advance
- Announce planned downtime ahead of time on the status page and community Discord, and make the operating procedures tell planned maintenance apart from service disruptions
- Finish the database sharding project so apps can use different databases and configuration changes can go through canary and blue/green setups
- Finish building a zero-downtime database failover system
- Set much higher scaling floors on the compute autoscalers
- Lessons
Gadget names three deeper factors. Choosing the in-place restart put the database into a state the team had not seen before and was not confident in. Capacity planning for Black Friday / Cyber Monday assumed a doubling of traffic instead of the almost 5x that came, so settings such as max_connections stopped fitting and had to be changed in an emergency instead of in a maintenance window practised in staging. And there was no way to test database configuration changes in a production-like environment: integration tests run against a synthetic Postgres database that never goes through the months of production load behind the memory fragmentation or the memory usage issues.
IL-0308Most RevenueCat backend systems failed after cutover to a new Aurora PostgreSQL 14 cluster as queries became very slowRevenueCat2022- Symptoms
At 9:34 UTC on November 23, 2022, RevenueCat started moving traffic from its Aurora PostgreSQL 10.x cluster to a new Aurora PostgreSQL 14.x cluster. By 9:39 UTC all traffic was on the new cluster, latency was bad, and the RevenueCat dashboard and the endpoints used by the RevenueCat SDK stopped working.
- Trigger
At 9:34 UTC production traffic was switched from the Aurora PostgreSQL 10.x cluster to the new Aurora PostgreSQL 14.x cluster, before ANALYZE had run on its largest tables.
- Root cause
- Component
- Contributing factor
- Detection
At 9:39 UTC, with all traffic on the new cluster, latency looked bad and the infrastructure team began to investigate.
- Remediation
- Added a statement timeout to the database user so queries could not hold a connection too long
- Shed 90% of traffic by returning 503s from the load balancer
- Dropped indexes that the planner was using wrongly and that were not needed
- Stopped accepting Apple webhooks for a time
- Rolled out a release without New Relic to stop its EXPLAIN queries
- Ran ANALYZE by hand on the biggest tables
- Raised the values of the affected primary key sequences with a prepared script
- Stopped the integration event dispatcher by hand
- Replayed the webhooks that were dispatched but not recorded
- Restored integration event dispatching, ETLs and other non-web server jobs
- Action items
- Consider change freezes during business-critical periods
- Explain better how the SDK behaves during backend outages
- Tell customers about maintenance and outages in the developer dashboard and by direct email to technical contacts
- Replay a subset of write traffic in migration dry runs to mimic the cutover
- Move costly processes to asynchronous work to keep the API fast and stable
- Re-evaluate table indexes, including unused ones the database may choose for queries
- Show the load of each endpoint and system in the database dashboards
- Involve support and customer communications staff during outages
- Lessons
The new cluster had not been analyzed, and the tests missed it because the test cluster had been up long enough to gather statistics. Dry runs replayed no write traffic, on the belief that writes are simpler than reads, and the team assumed sequence state was replicated with the data. Rolling back at the start would have been better than fixing forward. The migration, timed to finish before Thanksgiving and Black Friday, should have been delayed until the week after, because the US had entered a sensitive period and part of the US support team was already on holiday.
These 3 cases involve Database and Database proxy and connection pooler. kubegap audits a Kubernetes cluster for gaps like these, read-only, from Claude Code or Codex; its checks cite public reports like the ones in this library.
By root cause3
Software defect1 case
- Contributing factor
- Organisation
Capacity exhaustion1 case
- Contributing factor
- Organisation
Breaking change in an upgrade1 case
- Component
- Contributing factor
- Organisation