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.
What would it look like to treat runbooks as code: version-controlled, linted, and tested in CI before a change can merge? Walk through how you'd implement that, and how you'd keep thousands of runbooks discoverable enough that an on-call engineer can find the right one within a couple of minutes.
Sample Answer
Direct answer
Store runbooks as Markdown with structured YAML front-matter in one canonical git repository, gate every change behind CI that lints and schema-validates the metadata and dry-run-tests any automatable step, and require review before merge, the same discipline as application code. Discoverability at scale comes from that same metadata: a required service field feeds a searchable index, and alert annotations link straight to the matching runbook, so an on-call engineer reaches the right doc from the page itself instead of searching for it.
Structured elaboration
CI pipeline
flowchart LR
A[Engineer edits runbook.md] --> B[Open PR]
B --> C[CI: lint YAML and Markdown]
C --> D[CI: schema-validate metadata]
D --> E[CI: dry-run automatable steps in sandbox]
E --> F{Checks pass?}
F -->|No| A
F -->|Yes| G[Owner review plus on-call ack]
G --> H[Merge to main]
H --> I[Publish to searchable index]
I --> J[Alert annotations link runbook URL]
Required metadata
| Field | Purpose |
|---|---|
| id | Stable identifier, referenced from alerts and postmortems |
| service | Ties the runbook to a service registry entry |
| owner | Team and on-call rotation responsible for upkeep |
| severity | Drives which validation tier and review gate applies |
| last_reviewed / last_verified | Freshness signal, updated only after a real validation pass |
| automatable | Whether any step can run through the execution platform |
Making thousands of runbooks findable in minutes
Every runbook's service field is validated against a central service registry at CI time, which catches typos and stale references after a rename. Alert rules carry the runbook's canonical URL in their annotations, so paging a human already surfaces the right doc; searching is the fallback path, not the primary one. A generated, always-fresh index, built from the same metadata at publish time, is searchable by service, tag, and severity, so finding the right runbook is a filtered lookup rather than full-text search over prose.
Rationalizing a messy legacy corpus
When inheriting hundreds of duplicated or contradictory legacy runbooks, don't try to review them all before migrating. Import everything into the new repo behind CI, then triage: retire clear duplicates, keeping the most-recently-verified version and redirecting the rest, and mark anything ambiguous as needing review with an expiry date so it doesn't sit unreviewed indefinitely. Treat the migration as incremental and CI-gated, not a one-time cleanup that has to finish before the new system can go live.
Linking postmortems back to runbooks
Postmortem action items that touch a runbook should reference the runbook's id field directly, not just link to it in prose. That makes it possible to build a reverse index of which incidents cited a given runbook's gaps, so recurring weak spots surface automatically instead of living only in scattered postmortem documents.
Worked example
A runbook's front-matter:
---
id: RB-DA-001
title: "Spark job failing with executor OOM"
service: data-ingest-pipeline
owner: team-data-platform
severity: P1
tags: [spark, etl]
last_reviewed: 2026-05-01
automatable: true
---
A PR that removes the owner field or sets severity: P5 (not a valid value in the schema) fails CI's schema-validation step with a specific, actionable error, rather than merging silently and leaving the on-call escalation path undefined for that runbook.
Trade-offs and pitfalls
- Over-engineering the schema so authoring a runbook feels like filing a support ticket discourages contributions; keep required fields minimal, owner, service, severity, last_reviewed, and let the rest stay freeform Markdown.
- Strict CI gating with owner review and on-call acknowledgment slows updates during an actual incident; document a fast-path for post-incident corrections that still requires review, just not before the fix ships in the moment.
- Building the search index without tying it to alerts leaves on-call still searching manually under pressure. The annotation link on the alert is what actually saves time; the index is the fallback.
How would you actually validate that your runbooks work before you need them in a real incident? Describe a program for testing them under realistic conditions.
Sample Answer
Direct answer
Validating runbooks before a real incident needs three ingredients: a way to safely exercise them, using sandboxes for non-destructive steps and canary execution for destructive ones; measurable acceptance criteria for what "verified" actually means; and a cadence that scales from cheap, frequent tabletop walkthroughs up to expensive, rare full game days. Treat validation as a graded ladder of increasing realism and cost, not a single all-or-nothing chaos exercise.
Structured elaboration
Ladder of validation
| Tier | What happens | Frequency | Blast radius |
|---|---|---|---|
| Tabletop read-through | Team reads the runbook aloud, checks it still matches current architecture | Monthly per critical runbook | None, discussion only |
| Sandboxed dry-run | Non-destructive or dry-run steps run against a synthetic or staging copy | Per runbook change, CI-gated | Isolated sandbox |
| Canary execution | The real, potentially destructive step runs against a single instance or shard in production | Quarterly for the highest-severity runbooks | One instance or shard |
| Full game day | The real trigger condition is simulated and the whole runbook runs end to end with the actual on-call rotation | Quarterly cross-team, and after major architecture changes | Scoped production traffic, with a kill switch |
Acceptance criteria for "verified"
- Every command in the runbook executed successfully against the environment matching its tier.
- Recovery met the documented RTO (recovery time objective: the maximum acceptable downtime) for that exercise.
- The person executing it was not the runbook's original author, which catches "only the author can actually run this" runbooks.
- No manual step was needed beyond what's written, which catches missing steps.
- The runbook's last-verified metadata is updated only after all of the above pass, tied to the specific commit that was tested.
Sandboxing and canary mechanics for destructive steps
- A dry-run flag on any script validates and logs without mutating anything; most cloud SDKs and infrastructure-as-code tools support this natively.
- Ephemeral, synthetic-data environments handle full destructive rehearsals safely, isolated by namespace or project and feature-flagged away from real customer traffic.
- Steps that can only be meaningfully tested in production, like a real failover, get a canary first: a single shard or instance, with an automated rollback path and a pre-agreed abort condition.
Error-budget gate before running in production
Before a production game day, confirm enough error budget remains to absorb the intended, and any accidental, impact. For a monthly SLO of 99.9 percent over a 30-day window, the allowed downtime is:
error budget=(1−SLO)×window minutes
(1−0.999)×43,200=0.001×43,200=43.2 minutes
If the remaining budget is close to that 43.2-minute figure, postpone the exercise rather than spend the safety margin on a drill.
Worked example
A cache-cluster failover runbook is canary-tested against a single shard. The failover command executes without manual intervention, recovery meets the documented RTO target, and the engineer running the drill is not the runbook's original author. All four acceptance criteria above pass, so the runbook's last-verified metadata is updated to the exact commit hash that was tested, and the result feeds into the quarterly decision of whether this runbook is due for a full game day next.
Trade-offs and pitfalls
- Relying only on tabletop reads because full game days are expensive means staleness in the actual commands never gets caught until a real incident does it for you.
- Letting the runbook's author be the only person who can successfully execute it means you've tested the author's tribal knowledge, not the documentation; a different operator running the drill is what actually validates the doc.
- Full production game days build the highest confidence but carry real risk and spend real error budget; the ladder exists so most validation stays cheap, and only the highest-severity runbooks earn a full game day.
How would you get a new engineer ready to join the on-call rotation? Walk through what you'd want them to do before their first solo shift.
Sample Answer
Readiness is a checklist, not a countdown: get access and tooling working first, have them study and sign off on the runbooks for their services, shadow several live pages, then run one supervised tabletop and one supervised live (or simulated) incident before they take a shift alone with a mentor reachable but not present.
A four-week ramp
| Week | Focus | Activities | Exit criteria |
|---|---|---|---|
| 1 | Access + orientation | Provision accounts/VPN/MFA/pager, architecture overview, assigned runbook study | All access verified, runbooks read |
| 2 | Guided practice | Shadow 3-4 live alerts with a mentor, pair on small remediation tickets | Runbook sign-offs for owned services |
| 3 | Increasing autonomy | Lead a staging fault-injection drill with mentor observing, handle 1-2 small solo operational tasks with review | Drill led successfully, gaps found in runbooks fixed |
| 4 | Supervised solo shift | First on-call shift with mentor reachable, pre-shift briefing and post-shift debrief | Mentor sign-off, at least one incident handled or correctly escalated |
Sign-off checklist before the first unsupervised shift
- Access confirmed end to end (paging tool, dashboards, deploy/rollback permissions) with a real test, not just "provisioned."
- Runbooks for their assigned services reviewed and any ambiguous steps flagged and fixed.
- At least one supervised tabletop and one supervised live or injected-fault incident completed.
- Mentor sign-off plus the engineer's own confidence self-assessment, not mentor judgment alone.
Extending the ramp for a complex or high-stakes service
Four weeks is often enough for a straightforward service, but for a complex hybrid-cloud system or one with many downstream dependents, add explicit competency checkpoints tied to named systems, for example certifying someone independently on the database failover path as a separate sign-off from general on-call readiness, rather than declaring them ready across the board at once. Longer term, treat the first 90 days as a structured mentorship arc rather than stopping at week four: scheduled 30/60/90-day check-ins, a second mentor pairing on a different service, and a distinct milestone for graduating from "supervised" to "primary" status rather than just a date on the calendar.
Trade-offs and pitfalls
Rushing readiness to fill a rotation gap is the most common failure mode, and it produces confident-sounding but wrong incident responses, which is worse than an obviously under-prepared response because it takes longer to catch. A checklist with no live-incident component only validates that someone can read, not that they can act under time pressure; keep at least one supervised live or simulated incident before signing off. Sign-off criteria should be service-specific rather than one generic "on-call ready" badge, since readiness on a well-instrumented service doesn't automatically transfer to a fragile legacy one with thin runbooks.
What's the difference between MTTD, MTTA, and MTTR? Given a short incident timeline, how would you calculate each, and what's a common mistake people make when interpreting these numbers?
Sample Answer
MTTD is how long a problem existed before anything noticed it. MTTA is how long a human took to acknowledge the alert once it fired. MTTR is how long it took to fully resolve once someone was working it. The most common mistake is reporting a single blended average and treating it as typical, when one long outage in the set is doing all the work.
Definitions
| Metric | Starts at | Ends at | What it measures |
|---|---|---|---|
| MTTD | Failure begins | Alert fires / someone notices | How good detection is |
| MTTA | Alert fires | Human acknowledges | How well paging and routing work |
| MTTR | Acknowledgment | Service fully restored | How fast the response process fixes it, once someone owns it |
(Some teams instead measure MTTR from detection to resolve rather than ack to resolve; either is defensible, but the convention has to be fixed and stated, because mixing them across teams silently changes what the number means.)
Worked example: one incident timeline
| Event | Time |
|---|---|
| Failure begins | 14:00:00 |
| Alert fires (detection) | 14:06:00 |
| Engineer acknowledges | 14:11:00 |
| Service restored | 14:47:00 |
Worked example: averaging across three incidents, and where it goes wrong
| Incident | MTTD | MTTA | MTTR |
|---|---|---|---|
| 1 | 6 | 5 | 36 |
| 2 | 2 | 3 | 20 |
| 3 | 15 | 8 | 54 |
The mean of 36.7 minutes is being pulled up almost entirely by incident 3's 54-minute outlier: the mean sits above two of the three data points (20 and 36), with only the outlier itself larger. The median of {20, 36, 54} is 36, the middle value itself rather than a value inflated by the outlier, so it is a better single-number stand-in for the typical incident than the mean. Reporting mean MTTR alone, without the incident count or a percentile, makes a single bad incident look like the typical case.
Trade-offs and pitfalls
Comparing MTTR across teams that use different start-point conventions is comparing two different metrics wearing the same name; agree on the convention org-wide before benchmarking teams against each other. A dropping mean MTTR can hide a rising incident count: if you're resolving more small incidents faster while one rare severe incident still takes hours, the mean improves and the tail risk hasn't moved at all. Improving MTTD without improving MTTA or MTTR just means you find out about the same slow response faster; treat the three as stages of one pipeline, not independent wins to report separately.
Why do runbooks tend to go stale in a large engineering org? What are the common root causes, and what would you actually do about each one?
Sample Answer
Direct answer
Runbooks go stale because nothing automatically ties them to the systems they describe: ownership is unclear, updates aren't triggered by the changes that invalidate them, and nobody is rewarded for maintaining them, so they drift silently until an incident exposes it. The fix for each cause is the same shape: build the update into a workflow that already has to happen, like a deploy, a PR review, or a drill, rather than relying on someone remembering.
Structured elaboration
| Root cause | Why it happens | What to actually do |
|---|---|---|
| No clear owner | Docs feel like everyone's job, so they end up being no one's | Assign a named owner (team and person) per runbook, visible on the doc itself |
| No trigger tied to system changes | Infra or config changes ship without a linked doc update | Require a runbook-touch check in review for infra changes that affect the documented procedure |
| Fragmented across tools | The same procedure exists in a wiki, a chat pin, and a repo, and they diverge | One canonical source, docs-as-code in git; other tools link to it instead of duplicating it |
| Hard to edit | Binary or WYSIWYG pages discourage small fixes | Markdown in git with a low-friction pull-request flow |
| Never verified | Nobody runs the steps until a real incident forces it | Scheduled tabletop or game-day drills that surface breakage before it matters |
| Incentives favor code over docs | Engineers are measured on features shipped, not documentation kept accurate | Include doc currency in the definition of done or the on-call handoff checklist |
Worked example
A payments team migrates from a single database instance to a managed cluster with a different failover tool. The failover runbook still references the old promote command. Nobody touches the runbook because the migration's review process had no requirement to touch documentation tied to it, which is exactly the "no trigger tied to system changes" row above. Months later, an on-call engineer hits a real primary failure, runs the stale command, gets an error, and has to rediscover the correct procedure live instead of following a runbook that already had it. The root cause traces cleanly to the missing trigger, not to the engineer who wrote the original doc.
Trade-offs and pitfalls
- Quarterly "please review this doc" reminders without a named owner tend to become checkbox theater: marked reviewed without anyone actually re-verifying the steps.
- Gating merges on documentation updates adds friction to every infra change; scope the gate to changes that touch a documented procedure specifically, or teams will route around it entirely.
Unlock Full Question Bank
Get access to all 44 On-Call Practices and Runbook Design interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.