On-call burnout is the silent killer of small engineering teams. You do not notice it until your best engineer quits and cites being woken up at 3 AM for the fourth time this week as the reason.
I was that engineer. Then I automated three things and cut my on-call pages by 70%.
The Problem: Alert Fatigue
Our monitoring stack was firing 40+ alerts per day. Most were noise:
- CPU spiked for 30 seconds then recovered
- A deploy triggered a memory warning that cleared in 2 minutes
- A cron job ran late by 5 minutes
- A health check failed once and then passed
Each alert paged someone. Each page cost 15-20 minutes of context switching. That is 10 hours per week lost to noise.
Automation 1: Alert Correlation (Saves 50% of Pages)
Instead of paging on every alert, group related alerts and only page if the group persists:
import time
from collections import defaultdict
alert_buffer = defaultdict(list)
ALERT_WINDOW = 300 # 5 minutes
def handle_alert(service, severity, message):
key = f'{service}:{severity}'
now = time.time()
# Prune old alerts
alert_buffer[key] = [t for t in alert_buffer[key] if now - t < ALERT_WINDOW]
alert_buffer[key].append(now)
# Only page if 3+ alerts in 5 minutes
if len(alert_buffer[key]) >= 3:
page_on_call(service, message)
alert_buffer[key] = [] # Reset after paging
else:
log_alert(service, message) # Log but do not page
This cut our pages by 50% overnight. Single blips get logged. Sustained issues get paged.
Automation 2: Auto-Acknowledge Self-Healing Alerts (Saves 15% of Pages)
Some alerts fire and then resolve themselves within 2 minutes. We added a 2-minute delay before paging:
import threading
def delayed_page(service, message, delay=120):
def page():
if not service_recovered(service):
page_on_call(service, message)
threading.Timer(delay, page).start()
# Every alert goes through delayed_page instead of page_on_call directly
If the service recovers within 2 minutes, no page. If it is still down, the page goes out.
Automation 3: Smart Escalation (Saves 5% of Pages)
When a page does go out, it goes to the primary on-call. But if the primary is already dealing with another issue, it auto-escalates to the secondary after 5 minutes instead of 15:
def escalate_if_busy(primary, secondary, issue_id):
if is_handling_issue(primary):
if time_since_page(issue_id) > 300: # 5 minutes
reassign_issue(issue_id, secondary)
notify(primary, f'Escalated {issue_id} to {secondary}')
The Results After 30 Days
| Metric | Before | After |
|---|---|---|
| Pages per day | 40+ | 12 |
| Pages between 11 PM and 6 AM | 8/night | 2/night |
| Time to acknowledge | 8 min avg | 3 min avg |
| On-call satisfaction (1-10) | 3 | 8 |
The On-Call Survival Pack
I packaged these automations (plus the alert correlation rules, escalation config, and a setup guide) into a starter kit:
It includes:
- Alert correlation script with customizable thresholds
- Self-healing alert delay timer
- Smart escalation rules engine
- A 30-day on-call audit template to measure your own burnout
On-call does not have to be a punishment. Three small automations can turn it from a 3 AM nightmare into a manageable part of your week.
More ops templates at hive80lab.gumroad.com.
Top comments (0)