Cases2 cases
1 to 2 of 2
IL-0497Buttondown's database ran out of connections twice in one day and requests failed while health checks mostly passedButtondown2026- Symptoms
On 31 March 2026 Buttondown was down twice, for about seven and about thirteen minutes. New requests could not get a database connection and failed, although the database itself was healthy: queries were fast, CPU and memory were fine and replication lag was nominal.
- Root cause
- Component
- Contributing factor
- Detection
User reports and the team's own manual observation, not automated monitoring. The health check endpoint kept returning 200 for most requests, so no alert fired.
- Remediation
- Killed active queries to free database connections in the first outage
- Restarted the database to force-kill the running queries in the second outage
- Action items
- Reserve a small number of database connections for administrative access
- Monitor and alert on the database connection count as a percentage of the configured maximum
- Make the health check endpoint run a lightweight query so connection exhaustion shows in the health checker and the load balancer
- Add database connection limits to the quarterly capacity review
- Document and script a fallback that force-recycles workers to release connections without needing a database connection
- Lessons
Buttondown notes that the tool used to recover from the first outage needed the same resource that was exhausted, which locked the team out during the second outage, and that a health check which cannot detect connection exhaustion, the most common failure mode, gives little protection. A configuration value set long ago drifted out of line with traffic because nobody reviewed it.
IL-0333A downsized RDS PostgreSQL database maxed out its CPU at US peak and failing ELB health checks took buildkite.com downBuildkite2016- Symptoms
On 22 August 2016 at 17:21 UTC buildkite.com went offline: nobody could log in, view build logs or read the documentation, although builds kept running and GitHub and Bitbucket pull request statuses kept updating. The Buildkite team in Melbourne was asleep and woke at 21:00 UTC, almost 4 hours later, to emails, tweets and Slack messages saying Buildkite was down.
- Trigger
Over a weekend maintenance window, Buildkite downgraded its m4.10xlarge Multi-AZ RDS PostgreSQL database to an r3.2xlarge Multi-AZ instance to cut its AWS bill, and moved to a centralised pgbouncer to pool connections. The first US weekday peak after the change pushed the new instance's CPU to its maximum at about 16:00 UTC.
- Root cause
- Component
- Contributing factor
- Detection
New Relic, Pingdom, Datadog, Calibre and CloudWatch raised PagerDuty alerts, but the on-call phone call never came and only silent push notifications arrived. The team noticed at 21:00 UTC when they woke to emails, tweets and Slack messages from users.
- Remediation
- Moved servers from the Agent API to the dashboard ELB to bring buildkite.com back online
- Switched the Auto Scaling Groups to EC2 health checks and locked in desired counts
- Upgraded the database to an instance type that could handle the load, using the aws-cli
- Built a new AMI that did not depend on buildkite.com/_secret/version and rolled out servers that could self-deploy
- Removed the centralised pgbouncer and went back to pgbouncer on each host
- Action items
- Plan load testing after significant infrastructure changes without affecting other users of the system
- Make the ELB health check return OK when the app answers, without checking database connectivity
- Consider a separate health check endpoint for Pingdom that checks the database and other dependencies
- Store the latest deployed revision as a file on S3 for newly launched servers to self-deploy from
- Test by hand that PagerDuty calls reach every on-call team member
- Investigate regular company-wide tests of everyone's paging setup
- Ask PagerDuty about calling members when they go on call or requiring an immediate phone rule
- Lessons
Buildkite listed six lessons. Watch AWS credits, because billing reports show $0 while credits are spent, so the real cost is hidden and big changes end up rushed. Load test after significant infrastructure changes. Think about what a health check should do and what happens when every server behind an ELB fails it. Do not make new servers look up the deployed revision from the service they are replacing. Make sure every on-call member has the right PagerDuty and phone settings before going on call. When servers churn in AWS, stop health checks and autoscaling, for example with the Auto Scaling feature to suspend and resume processes, so the EC2 request limit is not used up.
These 2 cases involve Database and Cloud load balancer. 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 cause1
Capacity exhaustion2 cases
- Contributing factor
- Organisation