Skip to content
ExponaBLOG
ENGINEERING CRAFT · DAY 036 / 100

Incident response at 3 AM: practical tips and trade-offs

What a calm incident looks like.

Expona Admin6 min read

The 3 AM alert that changes everything

Your phone buzzes. Payment processing is down. Customer support is drowning in tickets. The CEO is about to wake up to chaos. Incident response at 3 AM: practical tips and trade-offs isn't about being a hero—it's about staying methodical when everything feels urgent. We've all been there, and the difference between a 20-minute outage and a 3-hour disaster often comes down to process, not luck.

Understanding the incident flow

A calm incident follows a predictable rhythm. When things go sideways, most teams panic and jump straight to diagnosing root cause. That's backwards. Instead, structure your response around five distinct phases: detect, declare, mitigate, communicate, and resolve with follow-up.

Detect: An alert fires—a monitoring rule triggers, error rate spikes, or a customer reports data loss. The moment detection happens, a human needs to acknowledge it. In our production systems, we use PagerDuty to route alerts to an on-call engineer. No alert should sit in Slack unread for more than two minutes.

Declare: Once the alert is acknowledged, someone needs to decide: is this a real incident or a false positive? If real, one person becomes the incident lead. That's non-negotiable. At this stage, a brief Slack channel is created (e.g., `#incident-20240315-payments`) and the lead posts a single message: "Incident declared. Lead: @alice. Status: investigating." Everyone else knows exactly who to follow for decisions.

Mitigate: Stop the bleeding first. Don't spend 15 minutes finding root cause while customers lose money. Mitigate means: roll back the last deploy, disable the problematic feature flag, scale up the database, or circuit-break a failing dependency. Speed matters more than precision here.

Communicate: Every 5–10 minutes, the incident lead posts a status update. No lengthy paragraphs. Format: "Status: investigating / mitigating / resolved. Action: scaling API servers. ETA: 5 mins." This single message keeps executives, support, and engineering aligned without creating noise.

Resolve and follow-up: Once the system stabilizes, document what happened in a postmortem. Not next week—within 48 hours. Real incidents have root causes, and those causes become backlog items.

Mitigate before diagnosing

This is where most teams stumble. An engineer sees an error in logs and dives into code, trying to understand why. Meanwhile, customer requests queue up. The right sequence is different.

Consider a real scenario: your checkout page starts timing out. Error logs show database query slowness. You have two choices:

  1. Spend 30 minutes analyzing the slow query, tuning indexes, redeploying code.
  2. Immediately roll back the last deploy and get the site responsive again. Investigate the query tomorrow.

In a production incident, option 2 is almost always correct. A rollback takes 2–3 minutes. Root cause analysis takes hours. Your customers don't care about correctness; they care about availability.

Common mitigation strategies, in order of preference:

  • Rollback: The fastest option if a recent deploy is the culprit. Takes seconds to execute if your deployment process is automated.
  • Feature flag kill switch: If only one feature is broken, disable it in production without redeploying. This should be effortless—a single environment variable or config change.
  • Scale horizontally: Add more replicas, increase database read pool size, or spin up extra workers. Buys you time while you diagnose.
  • Circuit breaker or graceful degradation: If a downstream service is flaky, shed load or return a cached response. Don't let one failure cascade.
  • Database failover or backup: Switch to a read replica or restore from backup if data corruption is suspected.

Each of these keeps the system limping forward while investigation happens in parallel. This is the practical trade-off: you accept that the system isn't fixed, only stabilized, because stability for 90% of users beats correctness for 0% of users.

One incident lead coordinates everything

The biggest coordination failure we see is everyone investigating at once. Five engineers in Slack, four different hypotheses, no one deciding what to try next. Chaos.

The incident lead doesn't need to be the smartest person on call. They need to be the person who:

  • Says "stop, we're rolling back" and everyone stops.
  • Assigns specific tasks: "Alice, check database replication lag. Bob, review the last two commits. Carol, scale the API fleet."
  • Asks "do we have a hypothesis?" and "what's the next move?"
  • Prevents 10 people from debugging the same thing.
  • Keeps communication flowing to stakeholders.

A good incident lead doesn't investigate themselves. They coordinate investigators. If the incident lead is also neck-deep in logs, someone else should take over the leadership role. This sounds simple but requires deliberate rotation in on-call schedules. Your incident lead should have led at least a few incidents before—they need pattern recognition.

Set this up in your runbook or on-call documentation:

typescript
// incident-declaration.ts - shared in your on-call docs
interface IncidentDeclaration {
  incidentId: string;           // 20240315-payments
  leadName: string;             // who's in charge
  severity: 'critical' | 'high' | 'medium';
  detectionTime: Date;
  slackChannel: string;         // #incident-20240315-payments
  roleAssignments: {
    [key: string]: string;      // "logs" -> "alice", "database" -> "bob"
  };
}

// Example declaration message for Slack
const declaration = `
🚨 Incident Declared
ID: 20240315-payments
Lead: @alice
Severity: critical
Status: mitigating

Assignments:
• Logs & errors: @bob
• Database checks: @carol
• Feature flags: @dave

Slack channel: #incident-20240315-payments
Next update: 03:47 UTC
`;

Write as you go

The postmortem is infinitely easier if you document the incident timeline as it happens. Not perfect prose—quick, factual updates. Timestamp everything.

Example from a real incident:

03:42 — Alert fired: API error rate 45%. Lead assigned: alice. Channel created.
03:43 — Hypothesis: recent deploy caused memory leak in payment service.
03:44 — Action: rolling back to previous version.
03:46 — Rollback complete. Error rate still at 35%. Hypothesis rejected.
03:47 — New hypothesis: database connection pool exhausted. Checking logs.
03:50 — Confirmed: connection pool at max. Third-party API integration released leak 2 days ago.
03:51 — Mitigation: disabled third-party sync feature flag. Error rate dropping.
03:53 — Status normal. No more alerts. Full resolution in progress (monitoring code fix).
04:05 — Incident resolved. Root cause: missing connection pool close in SDK update.

This timeline—written in real time, not reconstructed later—makes the postmortem a 30-minute conversation instead of a three-hour detective hunt. It also shows where decisions went wrong. Did we waste time on the wrong hypothesis? Is that a systems design problem or a monitoring problem?

Create a template in your incident channel that auto-populates timestamp and format. Make it frictionless to add a one-liner every few minutes.

Common mistakes

Mistake 1: Waiting for perfect information before acting. If you're 90% sure a feature flag is the problem, kill it. Restore it in two minutes if you're wrong. The cost of hesitation is higher than the cost of a false positive.

Mistake 2: Declaring every alert an incident. Not every spike is a real outage. If error rate jumps 2% for 30 seconds, it's probably transient. Declaring an incident creates noise and incident fatigue. Reserve declarations for user-visible impact or data risk.

Mistake 3: Incident lead jumps into technical debugging. The lead should be asking "what's the next thing to try?" not "let me look at the code." As soon as the lead starts deep-diving, coordination breaks.

Mistake 4: No clear communication cadence. Updates every 2 minutes feel like spam. Updates every 15 minutes feel abandoned. Aim for 5–10 minute updates during active incidents, longer intervals as things stabilize.

Mistake 5: Skipping the postmortem. An incident without a postmortem is a feature you get to debug again in six months. Postmortems aren't blame sessions—they're process improvements. "Why did we not catch this earlier?" is a better question than "who broke it?"

Key takeaways

  • Structure incident response in five phases: detect, declare, mitigate, communicate, resolve. Skip none of them.
  • Mitigate before diagnosing. Stop the bleeding (rollback, kill switch, scale) while investigation runs in parallel.
  • One incident lead coordinates. Everyone else has assigned tasks. No lead = chaos.
  • Write the timeline as events happen. Future-you will thank present-you during the postmortem.
  • Speed of mitigation matters more than certainty. A quick rollback beats a perfect diagnosis.
  • Postmortems are process improvements, not blame. Treat them as opportunities to reduce incident frequency.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles