On-Call Engineering

Design on-call rotations that are sustainable, effective, and respectful of engineers' time. Covers rotation design, escalation policies, runbook standards, compensation models, and preventing on-call burnout.

On-call engineering is the discipline of ensuring systems remain stable, observable, and recoverable when engineers are not at their desks. It matters when a service fails at 2 a.m., when a database replica falls out of sync during a deployment, or when a third-party API begins returning 500s across a region. It is the practice of structuring responsibilities, tooling, and workflows so that anyone on-call—regardless of depth of domain knowledge—can triage, diagnose, and resolve incidents efficiently.

Incident Response Workflow

When an alert fires, the on-call engineer must act quickly. The goal is to reduce mean time to acknowledge (MTTA) and mean time to resolve (MTTR) through a well-structured, repeatable process.

  1. Acknowledge the alert within 15 minutes of its first occurrence.
     curl -X POST \
       -H "Authorization: Bearer $ONCALL_TOKEN" \
       -H "Content-Type: application/json" \
       -d '{"incident_id": "INC-2023-087", "acknowledged_by": "sarah", "notes": "Initial triage: system is unresponsive."}' \
       https://alerting.internal/api/v1/incidents/acknowledge
  1. Diagnose the root cause using layered visibility:
     # Retrieve logs from the past 10 minutes using structured JSON logs
     kubectl logs deployment/api-gateway -n prod --since=10m --tail=100 | jq '.timestamp, .level, .message, .error, .trace_id'
  1. Apply a fix based on the diagnosis:
       systemctl restart api-gateway
       kubectl rollout undo deployment/api-gateway -n prod --to-revision=12
       kubectl scale deployment/api-gateway -n prod --replicas=8
       # /etc/config/api-gateway.yaml
       connection_pool:
         max_connections: 150
         idle_timeout: 300s
         max_lifetime: 1h

Apply with systemctl reload api-gateway.

  1. Verify the fix and update the incident:
     curl -v https://api.example.com/v1/users/123

On-Call Rotation and Scheduling

An effective on-call rotation ensures consistent coverage and reduces burnout. The system must define who is on-call, when, and how they are notified.

  {
    "name": "API Team",
    "frequency": "weekly",
    "start_time": "2023-10-01T00:00:00Z",
    "rotations": [
      {
        "start": "2023-10-01T00:00:00Z",
        "end": "2023-10-08T00:00:00Z",
        "oncall": "alice",
        "backup": "bob"
      },
      {
        "start": "2023-10-08T00:00:00Z",
        "end": "2023-10-15T00:00:00Z",
        "oncall": "bob",
        "backup": "charlie"
      }
    ]
  }
  # Update on-call roster using a script triggered by CI/CD
  curl -X POST \
    -H "Content-Type: application/json" \
    -d '{"team": "api", "current_oncall": "alice", "start": "2023-10-01T00:00:00Z"}' \
    https://oncall.internal/api/v1/rotation

Alerting Configuration

Alerts must be actionable, timely, and avoid noise.

  alert: "High Error Rate in API Gateway"
  description: "API Gateway returns >5% errors over 5 minutes."
  severity: "critical"
  query: |
    rate(errors{service="api-gateway"}[5m]) / rate(requests{service="api-gateway"}[5m]) > 0.05
  for: "5m"
  labels:
    team: api
    service: api-gateway
  annotations:
    summary: "High error rate on {{ $labels.service }}"
    description: |
      API Gateway error rate has exceeded 5% over the last 5 minutes.
      Current value: {{ $value }}
      More details: https://monitoring.internal/incidents/{{ $labels.incident_id }}

Incident Documentation and Postmortems

Every incident is a learning opportunity. The documentation must capture not only what happened but why.

    # Postmortem: High Latency on Checkout Service (2023-10-04)

    ## Timeline
    - 02:15:42: Error rate spikes to 12%
    - 02:18:10: First alert fired
    - 02:20:03: On-call engineer acknowledges incident
    - 02:23:45: Logs show slow DB queries in `checkout` service
    - 02:31:00: DB index created; latency drops
    - 02:45:00: Incident resolved

    ## Root Cause
    - Missing index on `orders` table for `user_id` and `status`
    - Query: `SELECT * FROM orders WHERE user_id = ? AND status = 'pending'` took 800ms
    - Index created during previous deployment but not applied to production

    ## Actions Taken
    - Added index on `orders(user_id, status)`
    - Verified query performance with `EXPLAIN ANALYZE`
    - Updated deployment script to include index creation

    ## Lessons Learned
    - All database migrations should include a migration status check.
    - Add alert for "missing index" on high-load tables.
    - Include DB schema changes in deployment checklist.

On-Call Engineer Responsibilities

The on-call engineer is responsible for more than just responding to alerts.

      [INC-2023-087] High Error Rate in API Gateway

      Acknowledged by sarah (on-call)
      Status: In progress
      Summary: Error rate > 5% over 5 minutes.

      Next steps:
      - Investigate database queries
      - Check load balancer health
      - Review recent deployments

Common Pitfalls and Silent Failures

    [Unit]
    Description=API Gateway

    [Service]
    ExecStart=/usr/bin/api-gateway --config /etc/config/api-gateway.yaml
    WorkingDirectory=/opt/api-gateway
    Restart=always

Tooling and Data Flow

On-call engineering relies on a few core tools and data flows.

    CREATE TABLE alerts (
      id SERIAL PRIMARY KEY,
      incident_id VARCHAR(64) UNIQUE,
      title TEXT,
      description TEXT,
      severity TEXT,
      status TEXT, -- pending, acknowledged, in_progress, resolved
      created_at TIMESTAMPTZ,
      updated_at TIMESTAMPTZ,
      acknowledged_by TEXT,
      resolved_by TEXT
    );
    CREATE TABLE incidents (
      id SERIAL PRIMARY KEY,
      incident_id VARCHAR(64) UNIQUE,
      title TEXT,
      description TEXT,
      status TEXT,
      created_at TIMESTAMPTZ,
      acknowledged_at TIMESTAMPTZ,
      resolved_at TIMESTAMPTZ,
      root_cause TEXT,
      solution TEXT,
      follow_ups JSONB,
      logs JSONB,
      traces JSONB
    );

On-call engineering is not a role—it is a process, a culture, and a system. It thrives when every engineer knows how to respond to an alert, every incident is documented, and the handover between shifts is seamless. It is not enough to have alerts; the system must be designed so that anyone can become an on-call engineer after a single shift.

This page was rewritten on 17 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.