Alerting & Incident Response
The Beautiful Dashboard That Nobody Watches
Your monitoring setup is gorgeous. Grafana dashboards with perfect visualizations. Metrics flowing in from every service. Logs are centralized and searchable. Youâve done everything right.
Then 2 AM arrives. Your database fills up to 99% capacity. The application starts queueing requests. Response times triple. Customers start complaining on Twitter: âIs your service down? I canât place my order.â
Your monitoring dashboard would have shown all of this if anyone were watching. But nobody was. A security camera pointed at an empty room is useless. What you need is alerting: automated systems that detect problems and notify the right person, at the right time, with enough context to act.
But hereâs the trap: bad alerting is worse than no alerting. Imagine 500 alert emails a day, 95% of them noise. Engineers stop reading them. The one critical alert gets lost in the inbox. This is âalert fatigue,â and itâs deadly.
The goal of alerting is simple but elusive: actionable alerts that wake the right person at the right time with enough context to start solving the problem.
What Makes a Good Alert?
Not every problem deserves an alert. Letâs clarify the distinctions:
Actionable: The alert should tell you what action to take. âDatabase is 95% fullâ is actionable (run the cleanup job, increase capacity, investigate large queries). âCPU is 78%â is not actionable (high CPU might not matter if error rates are normal). This is the distinction between alerting on symptoms vs. causes.
Urgent: Some problems need immediate attention (payment processing is down), others can wait until business hours (test environment metrics anomaly). If you alert on non-urgent things, people ignore them.
Contextual: The alert should include enough information to start investigating: which service? which endpoint? how many errors? affected how many users?
Letâs categorize alerts by severity:
- CRITICAL (P1): Pages someone immediately. Revenue impact, customer-facing outage, data loss risk. Example: âpayment processing error rate above 5%.â
- WARNING (P2): Should be investigated today. Degradation that isnât breaking things yet, but trending badly. Example: âdatabase query latency p99 above 2 seconds.â
- INFO (P3): FYI, for dashboards. Interesting events but not urgent. Example: â10 pods restarted in the last hour.â
Most teams make the mistake of alerting on too many things, expecting the on-call person to triage. This causes alert fatigue. Instead, be ruthless: only alert on things that genuinely need human intervention right now.
SLO-Based Alerting: Alert When It Matters
The most advanced teams donât alert on metrics; they alert on SLOs (Service Level Objectives).
An SLO is a commitment: â99.9% of requests will succeed within 200 ms, measured monthly.â This allows an error budget: 0.1% of requests can fail, or equivalently, 43 seconds of downtime per month (if measured continuously, not monthly).
Naive alerting: âError rate above 0.1%â â this goes off the moment you exceed budget, but by then youâre already affecting customers.
Burn rate alerting is smarter. It asks: âAt the current rate of burning through our error budget, when will we run out?â If we have 100 errors left in our budget for the month (30 days), and weâre currently burning 10 errors per minute, weâll run out in 10 minutes. Thatâs an urgent alert. If weâre burning 1 error per hour, we can wait for business hours.
SLO: 99.9% success rate
Error budget per month: 0.1% of requests
If we have 1M requests/day: 86,400 errors allowed per month
Burn rate alert rules:
- Short window (5 minute): If we burn 5% of budget per 5 min â alert
(Extrapolates to emptying budget in ~100 minutes)
- Long window (1 hour): If we burn 1% of budget per hour â alert
(Extrapolates to emptying budget in ~100 hours)
This catches both fast catastrophes (5 minute alert) and slow degradation (1 hour alert), without spurious alerts for tiny blips.
The Incident Response Lifecycle
When an alert fires, a sequence of events unfolds. Good organizations have practiced and refined this:
Detection
â
Triage (Is it real? How severe?)
â
Mitigation (Stop the bleeding)
â
Resolution (Fix the root cause)
â
Post-Mortem (Learn for next time)
Detection: The monitoring system notices the problem. This should be fast (minutes, not hours).
Triage: Is the alert real or a fluke? How many users are affected? Is it a complete outage or partial degradation? This usually takes 1-5 minutes for practiced teams.
Mitigation: Stop the bleeding immediately. This might be reverting a bad deploy, scaling up instances, rerouting traffic, or disabling a broken feature flag. The goal is to restore service to users ASAP, not necessarily to understand why it happened.
Resolution: Investigate the root cause and fix it properly. This is slower (hours, sometimes days) but prevents recurrence.
Post-Mortem: After the dust settles, the team meets to reconstruct the timeline, identify the root cause, and agree on action items to prevent it next time.
Alert Routing and On-Call
When an alert fires, who gets notified? This is handled by alert routing systems like PagerDuty, Grafana OnCall, or OpsGenie.
Typically, thereâs a rotating on-call schedule. MondayâFriday, the backend team rotates whoâs on-call. Weekends and nights might have a different schedule. The alert goes to the person currently on-call for that service.
Most teams use escalation policies:
- Alert fires at 2 AM.
- Page the primary on-call engineer.
- If they donât acknowledge within 5 minutes (maybe theyâre in the shower), page the secondary.
- If no one acks after 10 minutes, page the engineering manager.
- If still no response after 15 minutes, wake up the VP of Engineering (this rarely happens; it signals something catastrophic).
Good on-call tools have one-click mitigations: acknowledge alert (stop paging), snooze for 30 minutes (I see it and Iâm working on it, donât re-page), resolve alert (I fixed it).
Runbooks: Your Incident Playbook
An alert with no context is useless. âError rate spikingâ â now what? Instead, attach runbooks to alerts: pre-written instructions for what to check and how to respond.
A runbook for âPayment Processing Error Rate Above 5%â might look like:
ALERT: Payment Processing Error Rate Exceeds 5%
CONTEXT:
- Check recent deployments in #deployments Slack channel
- Check the payment service logs:
- Are there database connection errors?
- Are there timeouts from the payment gateway?
- Are there authentication failures?
MITIGATION (in priority order):
1. Check if a deploy happened in the last 30 minutes
- If yes, consider rolling it back immediately
- Command: kubectl rollout undo deployment/payment-service
2. Check database connections
- Command: SELECT COUNT(*) FROM pg_stat_activity
- If above 200, we're hitting connection limit (max is 250)
- Action: Scale up RDS to larger instance type
3. Check payment gateway status
- Visit: https://status.stripe.com/
- If they're having issues, it will show there
- Action: Post to #incidents "Stripe having issues"
4. If none of the above:
- Join the #incidents Slack channel
- Page the payment team lead
- Escalation: VP Engineering if payment is still broken after 15 min
ESCALATION:
- If you can't reach anyone in 5 minutes, page up
- Incident commander: Call <on-call manager>
- Critical: Page the CEO (only if we're losing money this second)
FOLLOW-UP:
- After incident, create post-mortem ticket
- Assign to payment team
Great runbooks save 5-10 minutes on every incident. Over time, they accumulate into a tribal knowledge that new engineers can leverage.
Pro Tip: Keep runbooks next to your alerts. In Grafana, add a link to the runbook in the alert annotation. When the alert fires, the engineer sees the runbook right there, not buried in a wiki somewhere.
Incident Severity Classification
Not all incidents are equal. The industry standard is SEV-0 through SEV-4:
- SEV-0 (Critical): Complete outage, many users affected, revenue impact. CEO should be informed. All hands on deck. Page everyone.
- SEV-1 (Urgent): Significant impact, some users affected, major degradation. Page on-call team, engineering leads. Expect updates every 15 minutes.
- SEV-2 (Major): Moderate impact, limited users affected. Page relevant service team. Updates every hour.
- SEV-3 (Minor): Small impact, few users affected, mostly annoying. Create ticket, notify team, investigate when you have capacity.
- SEV-4 (Informational): No user impact, just tracking it. Ticket only.
The triage process (first 5 minutes) determines the severity. This informs how many people get paged, how quickly theyâre expected to respond, and when escalation happens.
The Incident Commander Role
In SEV-0 incidents, a senior engineer becomes the âIncident Commanderâ (IC). Their job is not to fix the problem (let specialists do that) but to orchestrate:
- Keep a timeline of events (for the post-mortem)
- Coordinate between teams (database, backend, frontend, etc.)
- Update stakeholders and customers (via status page)
- Make decisions if there are conflicts
- Escalate if needed
The IC is not the person deepest in the problem; theyâre above the fray, organizing. Good IC training is invaluable for big incidents.
Post-Mortems: Learning From Failure
After an incident is resolved, schedule a post-mortem meeting (within 24 hours while details are fresh). The goals:
-
Reconstruct the timeline: What happened? 2:00 AM â deployment. 2:03 AM â error rate spikes. 2:05 AM â alert fires. 2:10 AM â engineer acknowledged alert. 2:15 AM â root cause identified (query N+1). 2:45 AM â fix deployed. 3:00 AM â error rate back to normal.
-
Find the root cause: Not âwe deployed bad codeâ (symptom) but âwe didnât run the new query against production-size data before deployingâ (root cause).
-
Be blameless: The goal is to learn, not to blame individuals. âWhy did the engineer deploy without testing?â â âBecause our testing process doesnât catch N+1 queries. How do we fix that?â
-
Action items: Concrete things to prevent recurrence. âAdd a query performance check to the CI pipeline.â âIncrease deployment tests for database queries.â
Follow the â5 Whysâ technique:
Problem: Payment processing failed
Why? Error rate spiked to 50%
Why? Database query was slow
Why? We added a loop that queries the database per-item
Why? The engineer didn't test against production data volume
Why? Our staging environment is 10x smaller than production
Root cause: Staging environment doesn't match production, so issues don't surface before deployment
Action: Sync staging and production data weekly, or use a production clone for critical tests.
Good post-mortems create institutional memory. New engineers read past post-mortems and avoid the same mistakes.
Did You Know? Some teams have monthly âChaos Engineering GameDaysâ where they intentionally break things in production (in a controlled way) to test alerting, incident response, and runbooks. Itâs like a fire drill for your infrastructure. These reveal surprising gaps: alerts that donât fire, runbooks with wrong commands, on-call engineers who arenât actually contactable.
When Alerts Go Wrong
Alerting is hard. Common failures:
Alert fatigue: Too many alerts, most false positives. Engineers stop reading. The critical alert gets lost.
Cascading false positives: Service A health-checks Service B. Service B is briefly slow. Service A alerts. Service C health-checks Service A. Service C alerts. Suddenly you have 100 alerts for a 30-second hiccup in Service B. Use dependencies carefully.
Alerts that trigger the problem they measure: Monitoring is expensive. If your monitoring itself causes high CPU/memory, you might alert on the problem your monitoring created. Use passive monitoring where possible.
Alerts that canât be fixed immediately: If your alert requires a 2-hour manual procedure, paging someone at 2 AM is cruel. Use runbooks to enable fast mitigation, or donât alert (downgrade to SEV-3).
Trade-offs in Alerting
Sensitivity vs. Specificity: More sensitive alerts catch all problems but have more false positives. Less sensitive alerts miss some problems but are more actionable. Thereâs no perfect threshold; find the balance for your team.
Alert noise vs. on-call burden: Fewer alerts = happier engineers, but more incidents might slip through. More alerts = better detection, but increased on-call fatigue.
Alerting tool cost: PagerDuty, Grafana OnCall, etc., charge per incident or per user. Free tools have fewer features.
Engineer well-being: On-call is stressful. 2 AM pages damage sleep and morale. Invest in good runbooks, automation, and reasonable rotation periods. Most teams aim for 1 week on-call per month per engineer, with another on-call as secondary backup.
Key Takeaways
-
Alerting without monitoring is useless; monitoring without alerting is a security camera nobody watches. You need both.
-
Alert on symptoms (error rate), not causes (CPU usage). High CPU without user impact doesnât deserve an alert.
-
Alert on SLOs and burn rate, not arbitrary thresholds. This ties alerts to business impact and prevents alert fatigue.
-
Runbooks are your incident playbook. They save 5-10 minutes per incident and let junior engineers handle SEV-2s independently.
-
The incident response lifecycle â detect, triage, mitigate, resolve, post-mortem â turns incidents into learning opportunities. Blameless post-mortems build trust and prevent recurrence.
-
Test your alerts with GameDays. An alert that never fires might be broken. Chaos engineering catches these.
Practice Scenarios
Scenario 1: The 2 AM Payment Outage At 1:57 AM, your payment service error rate crosses 5%. The CRITICAL alert fires. The on-call engineerâs phone buzzes. She logs in and sees the runbook: âCheck recent deployments, check database connections, check payment gateway status.â
Deployment 30 minutes ago. She checks the payment service logs:
error_code="STRIPE_AUTHENTICATION_FAILED"
She checks Slack #deployments: âDeploy changed Stripe API key (updated in secrets manager).â But it looks like thereâs a mismatchâthe code is reading the old key from cache. She immediately escalates to the Stripe integration owner: âNew secret didnât get reloaded. Rollback or restart payment pods?â
They restart the payment pods. Within 2 minutes, error rate drops back to 0.1%. Full recovery in 12 minutes from initial alert. Later, post-mortem: âAdd a healthcheck that validates Stripe authentication on startup.â
Scenario 2: The Alert That Cried Wolf Your team gets paged on âAPI latency p99 above 2 seconds.â They check and itâs⌠fine. Error rate is normal, users are happy. The on-call engineer silences the alert and goes back to sleep. Three days later, the same alert fires during an actual degradation. Now the engineer is skeptical. âProbably another false positive.â Doesnât investigate. Customers get upset.
Lesson: Alert thresholds matter. Adjust the p99 threshold from 2 seconds to 3 seconds (was too sensitive). Or add logic: âonly alert if p99 is above 2 seconds AND error rate is above 1%.â This prevents false positives.
Scenario 3: The Cascade Service Aâs health check fails. Service A alerts. But Service A is actually fine; Service B (its dependency) is slow. Now the alerting system gets 50 alerts from all services that depend on B. The on-call engineerâs phone is buzzing constantly. Theyâve lost situational awareness.
Better approach: Service Aâs health check should report separately on its own health vs. its dependency status. It shouldnât alert on dependency slow-ness; the dependencyâs own alert should fire instead.
Next, we need to make sure services are actually alive and can accept traffic. This is where health checks come in.