Runbook: Database Failover¶
When to use: AWS RDS has triggered a failover (planned or unplanned) for one of the Chakra Commerce PostgreSQL instances. Services may be returning 5xx errors during the failover window (typically 30–60 seconds for RDS Multi-AZ).
Databases covered:
| Database | RDS Identifier | Service | Namespace |
|---|---|---|---|
| Orders Event Store | Not RDS — EventStoreDB on EKS | Orders | chakra-orders |
| Inventory PostgreSQL | chakra-inventory-postgres | Inventory | chakra-inventory |
| Customers PostgreSQL | chakra-customers-postgres | Customers | chakra-customers |
Step 1: Confirm Failover is in Progress¶
# Check RDS events for the affected instance
aws rds describe-events \
--source-identifier chakra-{service}-postgres \
--source-type db-instance \
--duration 60 \
| jq '.Events[] | {Message, Date}'
# Common event messages indicating failover:
# "Multi-AZ instance failover started"
# "DB instance restarted"
# "Multi-AZ instance failover completed"
A Multi-AZ failover is typically resolved within 60 seconds. If the event shows "failover completed" and services are still unhealthy, proceed to Step 2.
Step 2: Verify DNS Resolution After Failover¶
RDS Multi-AZ uses a CNAME that automatically updates to the new primary after failover. Services use the CNAME endpoint — not a direct IP. However, the application connection pool may be holding stale connections.
# Check the CNAME resolves to the new primary
nslookup chakra-{service}-postgres.cluster-xxxxx.{region}.rds.amazonaws.com
# Force connection pool refresh by rolling the pods
kubectl rollout restart deploy/{service} -n chakra-{service}
kubectl rollout status deploy/{service} -n chakra-{service}
Step 3: Verify Service Health After Pod Restart¶
# Check pods are running
kubectl get pods -n chakra-{service}
# Check database connectivity from the pod
kubectl exec -it deploy/{service} -n chakra-{service} -- \
node -e "require('./dist/health').checkDb().then(console.log)"
# Or use the health endpoint
curl -s https://internal.chakracommerce.internal/v1/{service}/health | jq .
Step 4: Check for Data Loss (EventStoreDB)¶
EventStoreDB (Orders) is not RDS and does not use Multi-AZ in the same way. It uses a 3-node cluster with leader election.
# Check EventStoreDB cluster state
kubectl exec -it eventstore-0 -n chakra-orders -- \
curl -s http://localhost:2113/gossip | jq '.members[] | {state, instanceId}'
# Expected: one member with state "Leader", others "Follower"
# If no leader for > 30 seconds: escalate to platform team
Step 5: Check for Outstanding Saga Compensation¶
If the Orders service lost connectivity to EventStoreDB or PostgreSQL during a saga (place-order flow), check for orphaned sagas:
# Find orders in AwaitingPayment state older than 5 minutes
# (These may have had payment captured but confirmation not yet appended)
kubectl exec -it deploy/orders -n chakra-orders -- \
node -e "require('./dist/tools/find-orphaned-sagas').run()"
Orphaned sagas require manual review by the orders-team lead.
Step 6: SLA Impact Assessment¶
Database failovers are the most common cause of latency spikes that exceed SLA targets. After recovery:
- Check the error budget remaining for the affected service in Grafana.
- If budget is < 20%: notify engineering VP and consider a feature freeze.
- Add a note to the post-incident review about the failover cause (AWS infrastructure event vs. operator error vs. known instance issue).
Prevention¶
- All services use RDS Multi-AZ (both primary and standby in separate AZs).
- Connection pools use
keepAlive: truewith a maximum connection age to avoid stale connections surviving a failover. - RDS Proxy is a future consideration — it maintains a warm connection pool and reduces failover client impact.