← Back to blog
sentinel

Getting Paged at 3am? Here's How to Fix It 10x Faster

Six simultaneous Slack alerts at 3am help nobody. Learn how correlated alerts, structured runbooks, and AI-powered incident summaries compress triage time from 30 minutes to 3.

on-callincident-responsealertingsentinelrunbooksdevops

Getting Paged at 3am? Here's How to Fix It 10x Faster



It is 3:07am. Your phone buzzes. Then buzzes again. Then again. You fumble it off the nightstand, squint at the screen, and see six Slack notifications from four different channels. One from your uptime monitor: "CRITICAL: api.yourapp.com is DOWN." One from your error tracker: "Alert: error rate exceeded 50/min in production." Two from your log aggregator: "Anomaly detected in api-main" and "Error spike: ECONNREFUSED." One from your cron monitor: "Missed heartbeat: process-payments job." And one from a teammate in a different timezone: "Hey, are you seeing 502s on the API?"

You are now awake. Your heart rate is elevated. You have six pieces of information, and you do not yet know if this is one problem or five. The next 20-30 minutes of your life will be spent not fixing the problem, but figuring out what the problem actually is. By the time you have correlated the signals, identified the root cause, and opened the right terminal, the issue has been affecting users for over half an hour.

This is the standard experience for on-call developers in 2026, and it is completely fixable.

The Real 3am Scenario



Let us walk through what actually happens when a production incident hits in the middle of the night, because the vendor marketing pages never show this part.

The First 60 Seconds



You are disoriented. You were in REM sleep four seconds ago. Your brain is operating at maybe 40% capacity. You tap the first Slack notification and see the uptime alert. Your immediate thought: "Is this a real outage or a blip?" You check the uptime monitor dashboard. The health check has failed three consecutive times over 90 seconds. This is real.

Minutes 2-5: The Correlation Dance



Now you need to understand scope. You open your error tracker -- there is a spike in ECONNREFUSED errors starting about 3 minutes ago. You open your log aggregator -- there are database connection timeout errors across two services. You check your cron monitor -- the process-payments job that runs every 5 minutes missed its last heartbeat. You check your deployment history -- there was a deploy at 11pm, four hours ago.

At this point you have five browser tabs open on your phone, you are trying to mentally correlate timestamps across different tools (each showing time in slightly different formats), and you still do not have a definitive root cause. You just know that multiple things are broken and they might be related.

Minutes 5-15: The Actual Diagnosis



You open your laptop. You SSH into the server or pull up your cloud dashboard. You check the database -- connection count is maxed out. You run SELECT count(*) FROM pg_stat_activity and see 100 active connections, which is the limit. You check which queries are holding connections -- there are 30 idle connections from the api-main service that were never returned to the pool. You check the deploy diff from 11pm. Someone (maybe you) merged a PR that introduced a code path where database connections are acquired but not released under certain error conditions.

Now you know the root cause. It took 15 minutes. The total incident duration is now approaching 20 minutes, and you have not started fixing anything yet.

Minutes 15-30: The Fix



You either roll back the deployment, hot-fix the connection leak, or manually kill the idle connections as a temporary measure. Then you verify the fix, confirm the health check is passing, and close out the alerts. Total time: 25-35 minutes. You go back to bed with adrenaline still coursing through your system and do not fall asleep for another hour.

If this scenario sounds familiar, you are not alone. We have talked to hundreds of developers and this pattern -- six alerts, manual correlation, slow diagnosis, fast fix -- is nearly universal. The fix itself usually takes 5 minutes. The triage takes 20.

The Mental Checklist Every On-Call Dev Runs



Whether they know it or not, every experienced on-call developer runs through the same mental checklist during an incident. Understanding this checklist is the key to automating it.

  • Is this real? Check if the alert is a false positive or transient blip.
  • What is the blast radius? Is it one service or multiple? Is it customer-facing?
  • When did it start? Find the first anomaly timestamp across all tools.
  • What changed? Check recent deploys, config changes, infrastructure changes.
  • What is the root cause? Correlate symptoms across monitoring tools to identify the underlying failure.
  • What is the fastest remediation? Rollback, hot-fix, restart, or scale up?
  • Is the fix working? Verify across all affected services that the problem is resolved.


  • Steps 1-5 are purely information gathering. They require no engineering skill -- just access to the right data and the ability to correlate it. This is exactly the work that AI can compress from 20 minutes to under 2 minutes.

    How Correlated Alerts Reduce Six Notifications to One



    The core idea is simple: instead of each monitoring tool independently firing alerts to your phone, a correlation layer sits between your monitoring tools and your notification channels. It collects all signals within a time window, identifies which ones share a common cause, and sends you a single alert with a complete picture.

    Here is what the difference looks like in practice.

    Without Correlation (Today)



    3:07:12 [Slack #alerts-uptime]    CRITICAL: api.yourapp.com DOWN (502)
    3:07:14 [Slack #alerts-errors]    Error rate spike: 52 errors/min
    3:07:18 [Slack #alerts-logs]      Anomaly: ECONNREFUSED in api-main
    3:07:22 [Slack #alerts-cron]      Missed heartbeat: process-payments
    3:07:25 [Slack #alerts-logs]      Error spike: ConnectionTimeoutError
    3:07:31 [Slack #alerts-uptime]    CRITICAL: billing.yourapp.com DOWN


    Six notifications. Three channels. Zero context about how they relate.

    With Correlation (Luxkern Sentinel)



    3:07:45 [Slack #incidents]

    INCIDENT: Database connection pool exhausted (prod-db-01) Confidence: HIGH | Affected services: 3 | Duration: 3m

    Root cause: PostgreSQL connections maxed (100/100). 30 idle connections from api-main not returned to pool.

    Affected: - api.yourapp.com (502s, 47 failed requests) - billing.yourapp.com (502s, 12 failed requests) - cron: process-payments (missed heartbeat)

    Last deploy: 11:02pm by ci/deploy (commit: fix-report-export) Suggested: Check connection release in fix-report-export diff

    [View raw signals] [Open runbook] [Acknowledge]


    One notification. One channel. Full context. You go from "what is happening?" to "I know exactly what is happening and what to do" in the time it takes to read a paragraph.

    The time saved is not incremental. It is the difference between a 30-minute incident and a 5-minute incident.

    The Runbook Template That Actually Gets Used



    Most teams have runbooks. Most runbooks are out of date, too long, or impossible to find at 3am. We have found that runbooks work when they are short, structured, and attached directly to the alert. Here is a template you can copy and adapt for your own services.

    # Runbook: Database Connection Pool Exhausted

    Severity: HIGH

    Services affected: api-main, worker-billing, cron jobs



    ---

    Step 1: Confirm (30 seconds)



    Run on the database server or via your database dashboard:

    SELECT count(*), state FROM pg_stat_activity GROUP BY state;

    If active + idle >= max_connections, the pool is exhausted.

    Step 2: Immediate Mitigation (2 minutes)



    Kill idle connections older than 10 minutes:

    SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle' AND query_start < NOW() - INTERVAL '10 minutes';

    Verify services recover by checking the health endpoint:

    curl -s -o /dev/null -w "%{http_code}" https://api.yourapp.com/health

    Expected: 200

    Step 3: Identify Leak Source (5 minutes)



    Check which application is holding connections:

    SELECT application_name, count(*) FROM pg_stat_activity GROUP BY application_name ORDER BY count DESC;

    If one service has disproportionately many connections, check its recent deploys for connection handling changes.

    Step 4: Permanent Fix



  • If caused by a code change: revert the deploy
  • If caused by load: increase max_connections or add
  • connection pooling (PgBouncer)
  • If caused by long-running queries: identify and optimize


  • Step 5: Verify Resolution



  • [ ] Health endpoints returning 200
  • [ ] Error rate back to baseline
  • [ ] Cron jobs running on schedule
  • [ ] Connection count below 80% of max


  • Escalation



    If not resolved within 15 minutes, escalate to: @backend-lead (phone) via Sentinel escalation


    The key properties that make this runbook usable at 3am:

  • Numbered steps with time estimates. You know exactly what to do in what order and how long each step should take.
  • Copy-pasteable commands. No pseudocode, no "run the appropriate query." Exact commands you can paste into a terminal.
  • Clear escalation criteria. If you have been working for 15 minutes and it is not resolved, escalate. No ambiguity.
  • Verification checklist. Do not close the incident until all four items are green.


  • You can attach runbooks like this to specific alert types in Sentinel, so when the AI identifies a database connection pool issue, the relevant runbook appears alongside the incident summary. No searching through Confluence or Notion at 3am.

    Setting Up Correlated Alerts



    If you are using Luxkern's monitoring tools, the correlation happens automatically because PingCheck, CronSafe, and LogDrain all feed into the same correlation engine. For third-party tools, you set up webhook ingestion. Here is how a typical configuration looks:

    // Configure alert correlation in Sentinel
    const sentinelConfig = {
      // Time window for grouping related alerts
      correlationWindow: "5m",

    // Minimum alerts before AI analysis triggers minSignalsForCorrelation: 2,

    // Notification preferences notifications: { // Send correlated summary, not individual alerts mode: "correlated",

    // Where to send channels: [ { type: "slack", channel: "#incidents", // Only HIGH and CRITICAL minSeverity: "high" }, { type: "phone", // Escalate to phone if not ack'd in 5 min escalateAfter: "5m" } ],

    // Quiet hours -- batch LOW severity alerts quietHours: { enabled: true, start: "22:00", end: "08:00", timezone: "Europe/Berlin", // During quiet hours, only page for HIGH+ batchLowSeverity: true } } };


    The quiet hours configuration is worth highlighting. Between 10pm and 8am, low-severity alerts are batched and delivered as a summary in the morning. Only high-severity and critical incidents page you. This alone can eliminate half of nighttime pages for most teams.

    Five Practices That Cut Incident Response Time



    Beyond tooling, here are five practices we have adopted that meaningfully reduce how long incidents take.

    1. Pre-Compute Your Deploy Diff



    When an incident fires, one of the first questions is "what changed?" If you have to open GitHub, find the right repo, look at recent merges, and read the diff, that is 3-5 minutes. Instead, have your CI pipeline post a deploy summary to a known location (a Slack channel, a webhook, or Sentinel directly) every time it deploys. Include the commit hash, the PR title, the files changed, and a link to the full diff. When the AI correlates an incident, it can immediately check if a recent deploy touched relevant code.

    2. Health Checks That Actually Check Health



    If your health endpoint is return 200, it tells you nothing. A useful health check verifies every critical dependency:

    app.get("/health", async (req, res) => {
      const checks = {
        database: await checkDbConnection(),
        redis: await checkRedisConnection(),
        externalApi: await checkStripeReachable()
      };

    const allHealthy = Object.values(checks).every((c) => c.ok);

    res.status(allHealthy ? 200 : 503).json({ status: allHealthy ? "healthy" : "degraded", checks, timestamp: new Date().toISOString() }); });


    When this health check fails, the response body tells you which dependency is down. The AI can use this to immediately narrow the root cause. We wrote about this in detail in our guide on monitoring API endpoints.

    3. Tag Alerts with Service Context



    Every alert should include the service name, environment, and dependency chain. Not just "HTTP check failed" but "HTTP check failed for api-main which depends on prod-db-01 and redis-cache-01." This metadata is what the correlation engine uses to link alerts together.

    4. Set Escalation Timers, Not Escalation Meetings



    Do not schedule a meeting to discuss an ongoing incident. Set a timer: if the incident is not acknowledged in 5 minutes, escalate to phone. If it is not resolved in 15 minutes, escalate to the next on-call. If it is not resolved in 30 minutes, escalate to the engineering lead. Automated escalation removes the social awkwardness of deciding when to wake someone else up.

    5. Write the Runbook During the Incident



    You will never write the runbook after the incident. You will mean to, but there will be a standup, then a planning session, then a new feature to build. Instead, as you are fixing the incident, paste the commands you ran into a document. After the incident, spend 5 minutes cleaning that document into a structured runbook. Attach it to the alert type in your incident tool. Next time this happens, the on-call engineer has a copy-pasteable guide.

    The Math on Response Time



    Let us put numbers to this. Here is a comparison of incident timelines with and without correlated alerts, based on real data from teams using Sentinel.

    | Phase | Without Correlation | With Correlation | |---|---|---| | Alert delivery | 1 min | 1.5 min (waits for correlation window) | | Understanding scope | 5-10 min | 0 min (included in alert) | | Identifying root cause | 10-20 min | 1-2 min (AI diagnosis) | | Finding remediation steps | 3-5 min | 0 min (runbook attached) | | Applying fix | 3-5 min | 3-5 min | | Verifying resolution | 2-3 min | 2-3 min | | Total | 24-43 min | 7-11 min |

    The correlation window adds 30-60 seconds of latency before the first alert is sent. This is a deliberate trade-off: you wait one extra minute at the start to save 15-30 minutes in triage. For a genuine emergency, 60 seconds of additional latency is negligible compared to 20 minutes of manual correlation.

    Understanding SLA implications of these response times is important too. If you are running a service with 99.9% uptime SLA, the difference between a 40-minute incident and a 10-minute incident is the difference between consuming your entire monthly error budget and barely making a dent.

    Conclusion



    The 3am page is not going away. Services go down. Databases run out of connections. Deploys introduce bugs. What can change is how long you spend staring at your phone trying to piece together what happened. The tools to compress 30 minutes of triage into 3 minutes of reading a correlated summary exist now. The runbook templates to eliminate "what do I do next?" exist now. The quiet hours policies to stop low-severity alerts from waking you up exist now.

    You are going to get paged again. The question is whether the next page gives you six separate alerts and no context, or one message with the root cause, affected services, relevant deploy, and a runbook. That is a choice you can make today.