Stage 7 · Master
Observability & Developer Experience Metrics
Incident Response for Platform Teams
Platform incidents affect all teams. Runbooks, war rooms, status pages, postmortem template. Blameless culture. Platform on-call rotation.
Platform Incidents Are Different
Platform incidents have blast radius across ALL teams. A platform API outage blocks all deploys. ArgoCD down = no GitOps sync. Crossplane down = no new DBs. Platform incidents need: faster detection, broader communication, dedicated war room, platform-specific runbooks, platform on-call rotation.
| Aspect | Application Incident | Platform Incident |
|---|---|---|
| Blast Radius | Single service/team | All teams, all services |
| Detection | Service alerts, user reports | Platform SLI alerts, multiple team reports |
| Communication | Team Slack, PagerDuty | All-hands Slack, status page, email, statuspage.io |
| Resolution | Team owns fix | Platform team fixes, all teams wait |
| Postmortem | Team-level | Platform-wide, shared learnings |
| Prevention | Service-specific | Platform hardening, runbook updates |
Platform Runbooks
Every platform component needs a runbook: detection, diagnosis, mitigation, resolution, contacts. Runbooks live in Git, rendered in portal, linked from alerts.
# Runbook: Platform API High Latency
## Metadata
- **Component:** Platform API
- **Owner:** @platform-oncall
- **Severity:** Critical (blocks all deploys)
- **Last Updated:** 2024-01-15
- **Review Cycle:** Quarterly
## Symptoms
- Platform API p99 latency > 1s for 5 minutes
- Scaffold commands timing out
- ArgoCD ApplicationSet controller errors
- Multiple teams reporting "platform slow"
## Detection
- **Alert:** PlatformAPIHighLatency (PrometheusRule)
- **Query:** histogram_quantile(0.99, rate(platform_api_request_duration_seconds_bucket[5m])) > 1
- **Dashboard:** Grafana > Platform > API Latency
## Diagnosis Steps
1. **Check API pods:**
```bash
kubectl get pods -n platform -l app=platform-api
kubectl top pods -n platform -l app=platform-api
```
- Look for: OOMKilled, CPU throttling, restart loops
2. **Check dependencies:**
- PostgreSQL: `kubectl get pods -n platform -l app=postgres`
- Redis: `kubectl get pods -n platform -l app=redis`
- GitHub API: Check GitHub status page
3. **Check recent changes:**
- ArgoCD: `argocd app list | grep platform-api`
- GitHub: Recent PRs to platform-api repo
- ConfigMap changes: `kubectl get events -n platform --sort-by=.metadata.creationTimestamp`
4. **Check resource saturation:**
- Node CPU/memory: `kubectl top nodes`
- API server latency: `kubectl get --raw /metrics | grep apiserver_request_duration`
## Mitigation
### Immediate (5 min)
- [ ] Scale API replicas: `kubectl scale deployment platform-api -n platform --replicas=10`
- [ ] Enable read-only mode (if feature flag exists): `kubectl set env deployment/platform-api -n platform READ_ONLY=true`
- [ ] Communicate: Post in #platform-incidents, update statuspage.io
### Short-term (15 min)
- [ ] Identify root cause (DB, Redis, CPU, memory, downstream)
- [ ] Apply targeted fix (scale DB, clear Redis, rollback deploy)
- [ ] Verify latency returning to normal
### Long-term (1 hr)
- [ ] Full root cause analysis
- [ ] Preventive measures (autoscaling, circuit breakers, caching)
- [ ] Update runbook with learnings
## Contacts
- **Primary On-Call:** @platform-oncall (PagerDuty)
- **Secondary:** @platform-lead
- **DB Admin:** @dba-oncall
- **Infra Lead:** @infra-lead
- **Comms:** @platform-comms
## Escalation
- **15 min:** No progress → Page secondary + infra lead
- **30 min:** No progress → Page platform director + CTO
- **60 min:** No progress → All-hands war room
## Post-Incident
- [ ] Create incident record in incident.io
- [ ] Schedule postmortem within 48 hours
- [ ] Update runbook with new learnings
- [ ] Add preventive alerts if missing
Standardized runbook: metadata, symptoms, detection, diagnosis steps, mitigation phases, contacts, escalation, post-incident tasks.
War Rooms & Communication
- Dedicated Slack channel per incident: #inc-YYYYMMDD-platform-api
- Incident commander: Coordinates, communicates, decides
- Scribe: Documents timeline, decisions, action items
- Subject matter experts: DB, infra, networking, security as needed
- Communication cadence: Update every 15 min (or on major change)
- Status page: Update statuspage.io / Atlassian Statuspage every 30 min
- Customer comms: Email to stakeholders if >30 min impact
- All-hands: If >1 hour or customer-facing impact
# Incident Timeline: INC-20240115-001
## Summary
- **Incident ID:** INC-20240115-001
- **Title:** Platform API High Latency (p99 > 5s)
- **Severity:** SEV-1 (Critical)
- **Start:** 2024-01-15 10:23 UTC
- **End:** 2024-01-15 11:45 UTC
- **Duration:** 82 minutes
- **Commander:** @jane.platform
- **Scribe:** @bob.platform
## Timeline
| Time (UTC) | Event | Action | Owner |
|------------|-------|--------|-------|
| 10:23 | Alert fired: PlatformAPIHighLatency | PagerDuty alert to @platform-oncall | PagerDuty |
| 10:25 | On-call acknowledges | Joined #inc-20240115-platform-api | @jane.platform |
| 10:26 | War room created | #inc-20240115-platform-api | @jane.platform |
| 10:28 | Diagnosis started | Checked API pods, DB, Redis | @jane.platform |
| 10:32 | Root cause identified | PostgreSQL CPU 100% due to missing index | @jane.platform |
| 10:35 | Mitigation: Scale read replicas | `kubectl scale statefulset postgres-read -n platform --replicas=5` | @bob.platform |
| 10:40 | Latency improving | p99 dropped from 5s → 800ms | @jane.platform |
| 10:45 | Index added | `CREATE INDEX CONCURRENTLY...` | @dba.oncall |
| 10:50 | Latency normal | p99 < 200ms | @jane.platform |
| 10:55 | Monitoring confirmed | 15 min stable | @jane.platform |
| 11:00 | Incident closed | Status page updated, team notified | @jane.platform |
## Root Cause
Missing index on `audit_logs.service_name` caused sequential scan on 50M row table during scaffold audit logging.
## Action Items
- [ ] Add index to audit_logs table (DBA) - DONE
- [ ] Add query plan analysis to CI for audit logging queries (Platform) - IN PROGRESS
- [ ] Add alert for PostgreSQL CPU > 80% (Platform) - TODO
- [ ] Review all audit logging queries for indexes (Platform) - IN PROGRESS
## Communication Log
- 10:30: Statuspage.io updated: "Investigating platform API latency"
- 10:45: Statuspage.io updated: "Identified root cause, implementing fix"
- 11:00: Statuspage.io updated: "Resolved - Platform API latency restored"
- 11:05: #platform-updates: "Platform API latency incident resolved. Root cause: missing DB index. Postmortem scheduled."
- 11:15: Email to stakeholders sent
Structured timeline with timestamps, events, actions, owners. Used for postmortem and communication.
Status Pages & Customer Comms
- Use statuspage.io, Atlassian Statuspage, or custom
- Components: Platform API, Scaffold, GitHub Integration, ArgoCD, Crossplane, Preview Envs, Portal
- Incident types: Degraded Performance, Partial Outage, Major Outage, Maintenance
- Update cadence: Every 30 min during incident, immediately on resolution
- Subscriber notifications: Email, Slack, webhook, SMS for critical
- Post-incident: Update with root cause link, preventive measures
Blameless Postmortems
Blameless culture: focus on systems, not people. 'What failed?' not 'Who failed?'. Postmortem within 48 hours. Template ensures consistency.
# Postmortem: INC-20240115-001
## Overview
- **Incident ID:** INC-20240115-001
- **Title:** Platform API High Latency due to Missing DB Index
- **Date:** 2024-01-15
- **Duration:** 82 minutes (10:23 - 11:45 UTC)
- **Severity:** SEV-1
- **Author:** @jane.platform
- **Reviewers:** @platform-lead, @dba-lead, @infra-lead
## Impact
- **Services Affected:** Platform API, Scaffold, ArgoCD ApplicationSet, Crossplane
- **Teams Affected:** All 12 teams (blocked deploys, scaffold, preview envs)
- **Users Affected:** ~150 developers
- **Revenue Impact:** None (internal platform)
- **SLA Breach:** Platform API p99 latency SLO (99.9% < 500ms) breached for 82 min
## Timeline
[Link to timeline document]
## Root Cause
**Primary:** Missing index on `audit_logs.service_name` caused sequential scan on 50M row table during scaffold audit logging.
**Contributing Factors:**
1. New audit logging feature deployed without query plan review
2. No automated query plan analysis in CI
3. No alert on PostgreSQL CPU saturation
4. Audit logging writes synchronous in scaffold path
## What Went Well
- Alert fired within 2 minutes of latency spike
- On-call responded within 3 minutes
- War room established quickly
- Root cause identified in 9 minutes
- DBA available and responsive
- Fix applied and verified within 27 minutes of root cause
## What Went Poorly
- No automated query plan analysis in CI/CD
- No alert on PostgreSQL CPU saturation
- Audit logging synchronous in critical path
- No circuit breaker for audit logging failures
- Status page update delayed by 7 minutes
## Root Cause Analysis (5 Whys)
1. **Why high latency?** PostgreSQL CPU 100%
2. **Why CPU 100%?** Sequential scan on audit_logs table
3. **Why sequential scan?** Missing index on service_name column
4. **Why missing index?** Query plan not reviewed during audit logging feature development
5. **Why no review?** No automated query plan check in CI; manual review skipped due to time pressure
## Action Items
| # | Action | Owner | Due Date | Status | Tracking |
|---|--------|-------|----------|--------|----------|
| 1 | Add missing index on audit_logs.service_name | @dba.oncall | 2024-01-15 | ✅ Done | PR #1234 |
| 2 | Add query plan analysis to CI for all DB migrations | @platform-lead | 2024-02-01 | 🚧 In Progress | Issue #5678 |
| 3 | Add PostgreSQL CPU > 80% alert | @platform-oncall | 2024-01-22 | 📋 Planned | Issue #5679 |
| 4 | Make audit logging async with circuit breaker | @platform-lead | 2024-02-15 | 📋 Planned | Issue #5680 |
| 5 | Add query plan review to code review checklist | @platform-lead | 2024-01-22 | 📋 Planned | Issue #5681 |
| 6 | Review all existing audit logging queries for indexes | @dba-lead | 2024-02-01 | 📋 Planned | Issue #5682 |
## Lessons Learned
1. **Automate what humans forget:** Query plan analysis must be automated in CI
2. **Async by default:** Critical path operations should not block on observability
3. **Alert on symptoms, not just causes:** CPU saturation alert would have caught this earlier
4. **Invest in tooling:** Automated query analysis pays for itself in prevented incidents
## Appendix
- [Incident Timeline](link)
- [Grafana Dashboard Snapshot](link)
- [PostgreSQL Query Plans](link)
- [Related Incidents](link)
Comprehensive postmortem: impact, timeline, root cause, 5 whys, what went well/poorly, action items with owners/dates.
Platform On-Call Rotation
| Aspect | Recommendation |
|---|---|
| Rotation | Weekly primary + secondary, monthly shadow |
| Handoff | Friday 10am: outgoing briefs incoming (30 min) |
| Escalation | Primary → Secondary → Platform Lead → Director |
| Compensation | On-call pay + comp time (1.5x hours) |
| Tools | PagerDuty for paging, Slack for coordination, incident.io for tracking |
| Runbook Access | All runbooks in portal + offline PDF backup |
| Training | Quarterly incident drills, new hire shadowing |
| Metrics | Track: MTTA, MTTR, pages/week, page fatigue, handoff quality |
Incident Drills & Game Days
- Monthly: Tabletop exercise (30 min) - walk through runbook for random scenario
- Quarterly: Game day (2-4 hours) - inject real failures in staging: kill API pod, saturate DB, break ArgoCD, simulate GitHub outage
- Annually: Full disaster recovery drill - failover to backup region, restore from backup, verify RTO/RPO
- Participants: Platform team + 1-2 developers from different teams
- Scoring: Detection time, diagnosis accuracy, mitigation effectiveness, communication quality
- Follow-up: Action items tracked, runbooks updated, tooling improved
Platform incidents are product incidents. Invest in: runbooks, on-call, drills, observability, automation. The platform team's reliability IS the organization's deployment reliability.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.