On-Call Practices and Runbook Design Questions
Running a sustainable on-call function: rotation design, production-readiness handoffs, and authoring runbooks that let responders act quickly. Covers runbook automation, on-call culture, escalation-ready documentation, and readiness reviews before a service takes production traffic. The operational-preparedness discipline that makes incidents survivable.
Design the guardrails for a system that lets on-call engineers trigger automated runbook actions directly from an alert. How do you prevent a misfire, or a compromised trigger, from causing a bigger outage than the one it was meant to fix?
Sample Answer
Direct answer
Guardrails come from three layers working together: classify every automatable action by risk, reversibility and blast radius, so low-risk actions can run unattended while destructive ones require signed, multi-party approval; rate-limit and circuit-break execution so a misfiring trigger can't repeat itself into a bigger outage; and make every execution auditable and traceable to a specific signed, version-pinned runbook so a compromised trigger's blast radius stays bounded even if it does fire.
Structured elaboration
Threat model
- Misfire: a legitimate alert misclassifies severity or triggers the wrong action, such as restarting the wrong service.
- Compromised automation pipeline: an attacker forges or replays an alert to trigger a destructive action.
- Insider abuse: someone with legitimate access triggers an action outside its intended use.
Each needs a different control. Misfire needs validation and rate limits. Compromise needs signing and short-lived credentials. Insider abuse needs approval gates and an audit log that can't be edited after the fact.
Guardrail decision flow
flowchart TD
A[Alert triggers automated action] --> B{Reversible and low blast radius?}
B -->|Yes, low risk| C{Under rate-limit threshold?}
C -->|Yes| D[Execute in sandboxed, least-privilege runner]
C -->|No| E[Circuit-break: block further auto-actions]
B -->|No, high risk or destructive| F[Require signed approval from two operators]
F --> G{Approved within TTL?}
G -->|Yes| D
G -->|No| H[Escalate to human on-call, no auto-execution]
D --> I[Write signed, tamper-evident audit entry]
Core controls
- Risk classification: every automatable action is tagged low, medium, or high at authoring time, reviewed like code, based on reversibility and blast radius.
- Rate limiting and circuit breaking: cap executions per action per time window, and auto-disable an action after repeated failures instead of letting it keep firing.
- Signing and provenance: only signed, version-pinned runbook releases execute in production; the executor verifies the signature first, so a compromised trigger can request an action but can't smuggle in unreviewed logic.
- Least privilege and short-lived credentials: the executor pulls scoped, time-limited credentials per execution rather than holding standing broad access.
- Immutable audit trail: every execution, who or what triggered it, the parameters, and the outcome, is written to an append-only log kept separate from the systems it can act on, so it survives a compromise of the executor itself.
Worked example
| Action | Reversibility | Blast radius | Risk tier | Guardrail |
|---|---|---|---|---|
| Restart a single stateless pod | Fully reversible | One instance | Low | Auto-execute, rate-limited to one per 5 minutes per pod |
| Drop and rebuild a search index | Not reversible without a full rebuild | Whole service | High | Requires two signed operator approvals within a 10-minute TTL |
Consider an attacker who can forge an alert payload. Against the pod-restart action, they're bounded by the rate limit and the action's inherently small blast radius. Against the index-drop action, they're blocked at the approval gate no matter how convincing the forged alert looks, because approval requires a human signature that an alert payload can't fake.
Trade-offs and pitfalls
- Classifying everything as needing approval defeats the point of automation, which is unattended response to the common case. Keep destructive steps as a separate, explicitly gated action rather than bundling them with routine remediation, so most actions land in the low-risk tier by design.
- More approval gates reduce blast radius but increase mean time to remediate; mitigate by keeping the low-risk tier wide and reserving gates for the genuinely destructive minority.
- Signing the runbook but not validating its parameters leaves a gap: a signed, but freely parameterizable, action like "restart <service>" can still be misused if the parameter itself isn't checked against an allowlist.
How would you measure whether an on-call rotation is sustainable or quietly burning people out? What would you actually track?
Sample Answer
No single number proves burnout. Track three families of signals together: raw load (pages per person per week), response burden (after-hours percentage, time-to-resolve), and human signals (fatigue self-reports, PTO usage), and watch for the same people repeatedly crossing thresholds across categories, not just one bad week.
What to track
| Category | Metric | Sustainable guideline | What it flags |
|---|---|---|---|
| Load | Pages per primary on-call per week | Under ~10/week | Rotation or alert volume is too high |
| Load | Share of pages from one service | No single service over ~40% of team pages | One noisy service is dominating the rotation |
| Response burden | After-hours page percentage | Under ~25% | Sleep disruption, needs alert-hours review |
| Response burden | P90 time-to-resolve trend | Flat or improving | Chronic fatigue slowing responders, not just harder incidents |
| Human signal | Post-incident fatigue self-report (1-5) | Sustained score at or below 2 | Early warning before hard metrics move |
| Human signal | PTO usage on the rotation | Not declining quarter over quarter | People avoiding time off is a red flag, not a green one |
Worked example: reading a four-week rotation block
Suppose the primary on-call received a combined 88 pages across the last 4-week rotation block (one week per engineer).
Pages per on-call week=488=22 pages/week≈3.1/dayAgainst the roughly-under-10/week guideline, 22 pages/week is more than double, a sustainability flag on its own. If 39 of those 88 pages fired between 20:00 and 08:00:
After-hours share=8839×100≈44.3%well above the roughly-25% guideline, corroborating that this isn't just a high-volume rotation, it's specifically disrupting sleep.
Trade-offs and pitfalls
These metrics can be gamed by suppressing alerts; pair volume metrics with an independent audit (a sampled review of closed incidents) so under-alerting doesn't masquerade as improvement. Self-reported fatigue data is noisy and subject to survey fatigue itself; treat it as a leading indicator alongside hard metrics, not as the sole trigger for action. A single bad week (one major outage) will spike every metric at once; look for a sustained pattern across at least a full rotation cycle before concluding the rotation itself, rather than the incident, is the problem.
Describe your approach and boundaries for being on-call. What kinds of alerts should page you versus just show up in Slack or email, and how do you protect your work-life balance while still being reliable?
Sample Answer
Direct answer
My rule is: an alert pages me only if it's actionable, urgent, and real, meaning there's something I can actually do about it, it needs a response within minutes rather than hours, and it reflects genuine or imminent customer/business impact. Anything that fails one of those three tests goes to Slack or a ticket, not my phone. I protect my own sustainability by treating a repeatedly noisy page as a bug in the alert that needs fixing, not as a toughness test I'm supposed to pass.
Structured elaboration
The paging bar, in practice. Before an alert is allowed to page a human overnight, it should answer yes to all three:
- Actionable: is there a specific thing a person can do right now, or does it just need to be visible on a dashboard?
- Urgent: does waiting until business hours meaningfully worsen the outcome?
- Real: does it correlate with actual customer or business impact, not just an internal metric that moves for benign reasons?
Anything that's informational, non-urgent, or has historically resolved itself before a human could act belongs in Slack or a ticket queue, not a page.
Boundaries I set for myself and expect from a team:
- Rotation limits: a cap on consecutive on-call weeks and mandatory rest between rotations, so on-call load is a scheduling property of the team, not a matter of individual endurance.
- Compensation for the bad weeks: comp time or a stipend that scales with how bad the week actually was, so a rotation with three overnight Sev1s isn't treated the same as a quiet one.
- A standing agreement that any alert paging the same person more than once or twice without a code change in response gets flagged as noise to fix, not accepted as the cost of doing business.
- Tracking my own load: if my pages-per-week start trending up, that's something I bring to the team, not something I quietly absorb, because sustainable on-call is a team-level property (rotation depth, alert hygiene) and not an individual willpower contest.
Worked example
In a recent on-call rotation, an alert on a background job queue started paging me nightly around 2am even though the queue reliably drained on its own within a few minutes every time. I didn't just mute it and move on; I posted the pattern in our team channel with the timestamps and outcomes for the last several nights (fires, self-resolves, no human action taken each time), and we agreed together that the alert needed a sustained-duration requirement before it could page overnight, since a brief backlog wasn't actually urgent or actionable at 2am. I made the config change, had a teammate review it since it affected everyone's rotation, and rolled it out. The nightly pages for that specific alert stopped after the change. The underlying job still occasionally backed up during traffic spikes, but that now showed up as a daytime ticket for the team to investigate instead of an overnight page for whoever happened to be on call.
Trade-offs and pitfalls
- Pitfall: "I'm always reachable, page me for anything" sounds committed but actually signals a lack of judgment about what deserves urgency, and it's a fast path to burnout that eventually degrades response quality for the alerts that really matter.
- Pitfall: the opposite extreme, "I basically never get paged after hours," can mean either genuinely excellent alert hygiene or quietly under-covered risk; the honest answer distinguishes which one it is with a concrete example, not just an assertion.
- Trade-off: a team that pays well for on-call (stipends, real comp time) can sustain a slightly higher page volume than one that doesn't, but that changes how much noise is tolerable, not whether the actionable/urgent/real bar applies. A well-compensated but chronically noisy alert is still a bug to fix, not a cost center to accept.
You get paged: p95 latency for a service has spiked and the error rate is climbing, starting a few minutes after a deploy went out. Walk through what you actually do in the first few minutes: what you check, how you decide on a mitigation, and when you'd escalate.
Sample Answer
The first few minutes after a page are for narrowing down scope and cause fast enough to act, not for finding the root cause. I validate the alert is real, figure out how big the blast radius is, check whether it lines up with the deploy that just went out, and pick a mitigation I can undo, escalating the moment the clock runs out on any of those steps.
The first-minutes checklist
- Validate (0-2 min): confirm the page against the actual dashboard, not just the alert text. Is p95 latency and error rate really elevated right now, or is this a flapping alert that already recovered?
- Determine scope (2-5 min): is this one service, one region, or several services at once? Check whether other, unrelated-looking alerts fired in the same window, they're often the same root cause fanning out, not five separate problems.
- Correlate with the deploy (2-5 min): the timing (a spike a few minutes after a deploy) is a strong signal but not proof; pull the diff (code, config, feature flags, schema changes) to see if anything plausibly explains a latency or error increase.
- Choose a reversible mitigation (5-15 min): rollback if the deploy is the clear cause and rollback is safe and fast; scale out or shed load if the cause looks like saturation; flip a feature flag if the change is flag-gated. Prefer whatever gets users out of pain fastest and can be undone if it turns out to be wrong.
- Escalate on the clock, not on ego (by 15 min): if scope, cause, or mitigation isn't clear by 15 minutes, escalate, that's a threshold, not a judgment call to second-guess in the moment.
Decision flow
flowchart TD
A[Page: p95 latency + error rate up, deploy went out minutes ago] --> B[0-2m: Validate against real dashboards]
B --> C[2-5m: Determine scope: one service or several]
C --> D{Timing matches the deploy?}
D -->|Yes| E[Pull diff: code, config, feature flag, schema]
D -->|No| F[Check shared dependency: DB, network, upstream API]
E --> G[5-15m: Pick a reversible mitigation]
F --> G
G --> H{Recovering by 15m?}
H -->|Yes| I[Validate recovery, stand down, write timeline]
H -->|No| J[Escalate: page secondary and service owner, open incident]
Telling apart the three usual causes when several services fail together
When multiple services degrade at once, the fastest disambiguation is checking one thing first: are the affected services related by a shared dependency, or only by being on the same network path?
- Shared dependency outage (a database, cache, or upstream API multiple services call): errors cluster around calls to that one dependency across otherwise-unrelated services; the fix is usually failover or shedding load to the dependency, not touching the calling services.
- Network partition: services can't reach each other or a shared resource, but each service is individually healthy when checked in isolation (CPU, memory, internal logic all fine); the fix is on the networking layer, not application code.
- Code bug from the recent deploy: failures track cleanly to services that received the deploy, and services that didn't receive it stay healthy; the fix is rollback.
The tell is the failure pattern: dependency outages show a common downstream call in every affected service's error logs, network partitions show healthy services that simply can't connect, and deploy-caused bugs map exactly to the set of services the deploy touched.
Two scenario variants worth knowing
A gradual climb (latency creeping up over 20 to 30 minutes rather than spiking) usually points at a resource exhaustion pattern, a connection leak or a slowly growing queue, rather than a bad deploy; the checklist is the same but step 3 shifts from "what deployed" to "what's been running long enough to leak." A regional error spike on a payments API narrows scope immediately to that region's infrastructure or a regional dependency, and raises the severity bar (payments plus regional means check whether it's revenue-impacting before deciding the escalation urgency).
Trade-offs and pitfalls
The most common mistake under pressure is skipping validation and mitigating against the alert text instead of the live dashboard, which can mean fixing a problem that already resolved itself while missing the real one. The second most common mistake is treating the 15-minute escalation threshold as optional because "I'm close", escalating early and being wrong costs a few minutes of someone else's attention; escalating late during a real outage costs users.
Where's the line between an operational runbook and a security incident-response playbook, and how do you keep a responder from accidentally leaking something sensitive, like pasting a live credential, into a runbook they're editing during an incident?
Sample Answer
The line is intent, not tooling: a runbook assumes the failure isn't malicious and defaults to fast, reversible operational actions, while a security playbook assumes it might be and defaults to preserving evidence and escalating. The handoff between them has to be a written, specific trigger list, not a judgment call made under pressure.
Runbook versus security playbook
| Dimension | Operational runbook | Security playbook |
|---|---|---|
| Default assumption | Failure is a bug, capacity issue, or bad deploy | Failure may involve an actor with intent |
| Default first action | Restart, scale, roll back, mitigate fast | Isolate and preserve, don't destroy evidence |
| Who leads | On-call engineer or SRE | Security on-call; engineer supports under their direction |
| Speed pressure | Restore service as soon as possible | Get it right; evidence and scope matter more than speed |
Handoff triggers (explicit, not a judgment call)
- A known indicator-of-compromise match (signature, known-bad IP, tampered binary).
- Automated remediation failing repeatedly while a new suspicious artifact appears.
- Any sign of lateral movement or a cross-service authentication anomaly.
- Any alert crossing a predefined confidence-plus-impact threshold agreed with security in advance.
Handoff flow
flowchart TD
A[Runbook step in progress] --> B{Indicator of compromise?}
B -->|No| C[Continue runbook as operational issue]
B -->|Yes| D[Isolate and preserve evidence, non-destructive]
D --> E[Open incident ticket with artifacts]
E --> F[Notify security on-call, SLA clock starts]
F --> G[Security triages within SLA]
G --> H[Security leads containment and investigation]
H --> I[SRE executes infra changes under security direction]
Keeping a live credential out of the runbook in the first place
The mechanism isn't "tell people not to paste secrets," it's removing the need to. Runbooks reference secret IDs resolved from a vault at execution time, the same underlying mechanism used to control access to any sensitive step, so there's rarely a reason to type a raw value into the document at all. For the cases where a responder is genuinely debugging and tempted to paste a live value for reference, a secret-scanning check on the runbook-editing tool (pattern and entropy-based) that blocks the save and asks for a redacted reference instead is a cheaper and more reliable control than relying on discipline during an incident.
Trade-offs and pitfalls
Treating every operational failure as a potential security incident slows down the vast majority of pages that are genuinely just a bad deploy; keep the trigger list narrow and specific rather than "when in doubt, escalate." The more dangerous direction is the opposite: treating every alert as operational until proven otherwise is how evidence gets destroyed by a well-meaning restart before anyone realizes it mattered, so the trigger list has to be actively taught, not just written down somewhere. Keeping runbooks and playbooks in separate systems owned by separate teams is how the handoff criteria silently drift out of sync with what each team actually expects; version-control both in one place with cross-references and joint review.
Unlock Full Question Bank
Get access to all On-Call Practices and Runbook Design interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.