# Runbook: [Service Name] > **Version:** [1.0.0] > **Last Updated:** [YYYY-MM-DD] > **Owner:** [Team Name / Individual] > **Review Cadence:** [Quarterly / Bi-annual / Annual] --- ## Table of Contents 1. [Service Overview](#service-overview) 2. [SLOs & Error Budget](#slos--error-budget) 3. [On-Call Quick Reference](#on-call-quick-reference) 4. [Monitoring & Alerting](#monitoring--alerting) 5. [Common Failure Modes](#common-failure-modes) 6. [Detailed Troubleshooting Procedures](#detailed-troubleshooting-procedures) 7. [Escalation Paths](#escalation-paths) 8. [Recovery Procedures](#recovery-procedures) --- ## Service Overview ### Description [Briefly describe what this service does, its purpose, and the critical function it serves in the broader system architecture.] ### Architecture [High-level description of the service architecture — key components, dependencies, data flow, upstream/downstream services.] ### Owner | Field | Value | |-------|-------| | **Engineering Team** | [Team Name] | | **Team Channel** | [#slack-channel] | | **Primary DRI** | [Name / Role] | | **Service Catalog URL** | [https://link-to-service-catalog] | | **Code Repository** | [https://github.com/org/repo] | ### Links | Resource | URL | |----------|-----| | **Grafana Dashboard** | [https://grafana.example.com/d/...] | | **Datadog Dashboard** | [https://app.datadoghq.com/dashboard/...] | | **CloudWatch Dashboard** | [https://console.aws.amazon.com/cloudwatch/...] | | **Kibana / Logs** | [https://kibana.example.com/app/discover#...] | | **Jaeger / Tempo Traces** | [https://tracing.example.com/...] | | **PagerDuty Schedule** | [https://pagerduty.com/schedules/...] | | **Status Page** | [https://status.example.com/] | | **Runbook (this doc)** | [link] | ### Dependencies | Dependency | Criticality | Notes | |------------|-------------|-------| | [Database e.g. PostgreSQL] | Critical | [connection details, failover info] | | [Cache e.g. Redis] | High | [cluster info, eviction policy] | | [Queue e.g. Kafka] | High | [topic names, consumer groups] | | [External API] | Medium | [rate limits, quota info] | | [Auth provider] | Critical | [token expiry, rotation schedule] | ### Key Metrics | Metric | Target | Description | |--------|--------|-------------| | `[p99_latency_ms]` | < [500ms] | End-to-end request latency | | `[requests_per_second]` | [N] | Throughput | | `[error_rate]` | < [0.1%] | Ratio of 5xx responses | | `[cpu_utilization]` | < [80%] | Instance CPU usage | | `[memory_utilization]` | < [80%] | Instance memory usage | --- ## SLOs & Error Budget ### Service Level Objectives | SLO | Target | Window | Measurement Method | |-----|--------|--------|--------------------| | **Latency** | [99% of requests < 500ms] | [28 days] | [Histogram buckets / Prometheus] | | **Availability** | [99.9%] | [28 days] | [Ratio of successful requests] | | **Throughput** | [Handle N req/s] | [1 hour] | [Max RPS measured] | | **Freshness** | [Data < 5min old] | [1 hour] | [Lag monitoring] | ### Error Budget | Period | Budget | Remaining | Burn Rate | |--------|--------|-----------|-----------| | **28 days** | [0.1% = 43m 12s] | [XX.X% remaining] | [Alert if > 2x target] | ### Burn Rate Alerts | Severity | Burn Rate | Duration | Action | |----------|-----------|----------|--------| | **Warning** | [2x] | [1 hour] | Investigate | | **Critical** | [10x] | [6 minutes] | Page on-call | | **Critical** | [2x] | [6 hours] | Page on-call | --- ## On-Call Quick Reference > The commands below include read-only and mutating examples. Before any command that mutates production, apply the operational closure gate: verify current human authorization for the specific action and scope, record the target, affected population, maximum blast radius, success and abort/rollback criteria, rollback path, and stopping authority. If the gate cannot be satisfied, stop and hand off or escalate. ### How to Access ```bash # SSH to production instances ssh [user]@[bastion-host] ssh [instance-name].[region].internal # Kubernetes access kubectl config use-context [cluster-name] kubectl get pods -n [namespace] # Database access psql -h [host] -U [user] -d [database] ``` ### How to Restart ```bash # Restart application service sudo systemctl restart [service-name] # Roll restart Kubernetes deployment kubectl rollout restart deployment/[deployment-name] -n [namespace] kubectl rollout status deployment/[deployment-name] -n [namespace] # Safe restart with traffic drain ./scripts/safe-restart.sh [service-name] ``` ### Common Commands ```bash # Check service health curl -s http://localhost:[port]/health | jq . # View recent logs journalctl -u [service-name] --since "1 hour ago" -n 100 # Check current version [service-name] --version curl -s http://localhost:[port]/version | jq . # Check active connections netstat -anp | grep [port] | wc -l # Check disk space df -h /data ``` ### Common Issues at a Glance | Symptom | Try First | |---------|-----------| | Service returning 5xx | Check `/health` endpoint, restart service | | High latency on p99 | Check CPU/memory, database query times | | Alerts firing after deploy | Rollback to last known good version | | Database connection errors | Check connection pool, restart app | | Out of memory | Increase resources, rollback recent change | | TLS / certificate errors | Check cert expiry, restart with reload | --- ## Monitoring & Alerting ### Key Dashboards 1. **[Service Overview Dashboard](https://grafana.example.com/d/service-overview)** — Primary dashboard for latency, error rate, throughput, saturation (the Four Golden Signals). 2. **[Infrastructure Dashboard](https://grafana.example.com/d/infra)** — CPU, memory, disk, network I/O per instance/container. 3. **[Database Dashboard](https://grafana.example.com/d/db)** — Connections, query latency, replication lag, cache hit ratio. 4. **[Dependency Dashboard](https://grafana.example.com/d/deps)** — Upstream/downstream health, queue depths, API latency. 5. **[Business Metrics Dashboard](https://grafana.example.com/d/biz)** — User-facing metrics: signups, active users, conversion. ### Logging - **Log Aggregator:** [Kibana / Loki / CloudWatch Logs] - **Log Level:** [INFO in production, DEBUG on-demand] - **Structured Log Format:** [JSON] - **Log Retention:** [30 days hot, 90 days cold] - **Log Query:** [`{service="[service-name]"} | json`] **Useful Log Queries:** ```kql # All errors in last hour {service="[service-name]"} | json | level = "error" # Requests for a specific user {service="[service-name]"} | json | user_id = "[user-id]" # Trace a single request ID {service="[service-name]"} | json | trace_id = "[trace-id]" ``` ### Tracing - **Tracing Backend:** [Jaeger / Tempo / X-Ray] - **Sampling Rate:** [1% head-based, 100% for errors] - **Trace Query by Service:** [`service.name="[service-name]"`] ### Alert Rules | Alert Name | Condition | Severity | Auto-Close | |------------|-----------|----------|------------| | `[HighErrorRate]` | error_rate > [1%] for [5min] | Critical | [15min after recovery] | | `[HighLatency]` | p99_latency > [1s] for [5min] | Warning | [30min after recovery] | | `[LowDiskSpace]` | disk_usage > [90%] | Warning | [Disabled] | | `[ServiceDown]` | up{job="[service]"} == 0 for [1min] | Critical | [10min after recovery] | --- ## Common Failure Modes > Each failure mode is self-contained through mitigation. After any mitigation or recovery action, follow R-01 before declaring the incident resolved. > > Before executing any **Resolution** command, apply the operational closure gate: verify human authorization for the specific action and scope, record the target, affected population, maximum blast radius, success and abort/rollback criteria, rollback path, and stopping authority. These rows describe mitigation options, not permission to execute them. If the gate cannot be satisfied, stop and hand off or escalate. ### FM-01: Service Unreachable / High Error Rate | Field | Value | |-------|-------| | **Symptom** | `5xx` responses > [N]%, health check failing, pager alert firing | | **Likely Cause** | Recent deployment, resource exhaustion, upstream dependency failure | | **Diagnosis** | 1. Check `/health` and `/metrics` endpoints
2. Review recent deployments (`kubectl rollout history` or equivalent)
3. Check CPU/memory on instance
4. Check upstream dependencies (database, cache, external APIs)
5. Review recent logs for panic/OOM/panic | | **Resolution** | 1. **If caused by recent deploy:** Rollback immediately: `kubectl rollout undo deployment/[deploy]`
2. **If resource exhaustion:** Scale up: `kubectl scale deployment/[deploy] --replicas=[N]`
3. **If upstream failure:** Check dependency runbook, pager dependency owner
4. **Last resort:** Restart the service
5. If none of the above work, [escalate](#escalation-paths)
6. After mitigation, follow **R-01** before declaring resolved; retain **MITIGATING** or **MONITORING** and escalate if evidence is missing. | --- ### FM-02: High Latency | Field | Value | |-------|-------| | **Symptom** | p99/p95 latency exceeds SLO threshold, users report slowness | | **Likely Cause** | Traffic spike, database query degradation, slow upstream, GC pressure | | **Diagnosis** | 1. Check traffic volume vs baseline (is this a spike?)
2. Check database slow query log — `SELECT * FROM pg_stat_activity WHERE state = 'active'`
3. Check GC metrics (if JVM: `jstat -gcutil`, if Go: `go_memstats_gc_cpu_fraction`)
4. Check upstream dependency latencies
5. Review tracing dashboard for slow spans | | **Resolution** | 1. **Traffic spike:** Auto-scale groups should handle; manually increase replicas if needed
2. **Slow queries:** Kill runaway queries: `SELECT pg_terminate_backend(pid) WHERE ...`; add missing index
3. **GC pressure:** Increase heap/memory, tune GC parameters
4. **Upstream slow:** Circuit-breaker should trip; verify upstream health
5. **Temporary fix:** Rate-limit or shed non-critical traffic
6. After mitigation, follow **R-01** before declaring resolved; retain **MITIGATING** or **MONITORING** and escalate if evidence is missing. | --- ### FM-03: Out of Memory / OOM Killed | Field | Value | |-------|-------| | **Symptom** | Container/process killed, OOM in kernel logs, instance becomes unresponsive | | **Likely Cause** | Memory leak in code, traffic surge, insufficient resource limits | | **Diagnosis** | 1. Check `dmesg | grep -i oom` for kernel OOM killer messages
2. Check memory metrics via dashboard (heap vs non-heap if JVM)
3. Review recent code changes for potential memory leaks
4. Check if memory limit was recently reduced
5. Heap dump analysis (if available): `jmap -dump:live,format=b,file=heap.hprof ` | | **Resolution** | 1. **Immediate:** Restart the service to reclaim memory
2. **Increase limits:** Edit resource `limits.memory` for the container/Pod
3. If caused by code change: rollback the release
4. Schedule memory leak investigation with engineering team
5. Consider enabling memory request-based autoscaling
6. After mitigation, follow **R-01** before declaring resolved; retain **MITIGATING** or **MONITORING** and escalate if evidence is missing. | --- ### FM-04: Database Connection Pool Exhaustion | Field | Value | |-------|-------| | **Symptom** | Application logs show `connection refused`, `too many connections`, or `connection timeout` | | **Likely Cause** | Connection leak in application, insufficient pool size, DB restart | | **Diagnosis** | 1. Check active connections on DB: `SELECT count(*) FROM pg_stat_activity`
2. Check max connections: `SHOW max_connections`
3. Identify connections by application: `SELECT application_name, count(*) FROM pg_stat_activity GROUP BY 1`
4. Check if connections are idle-in-transaction: `SELECT * FROM pg_stat_activity WHERE state = 'idle in transaction'`
5. Review application connection pool metrics (hikariCP, etc.) | | **Resolution** | 1. **Emergency:** Kill idle connections: `SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle'`
2. **Kill idle-in-transaction:** Same as above with `state = 'idle in transaction'`
3. Restart the application to reset its connection pool
4. If leak persists, increase `max_connections` temporarily on DB
5. Schedule fix for connection leak (usually unclosed `Connection` / `Session` objects)
6. After mitigation, follow **R-01** before declaring resolved; retain **MITIGATING** or **MONITORING** and escalate if evidence is missing. | --- ### FM-05: Disk Space Full | Field | Value | |-------|-------| | **Symptom** | Disk usage alert firing, application unable to write logs/data, `no space left on device` | | **Likely Cause** | Logs not rotated, data not cleaned up, unexpected large files (core dumps, heap dumps) | | **Diagnosis** | 1. `df -h` to identify full partition
2. `du -sh /* 2>/dev/null` to find large directories
3. `du -sh /var/log/* | sort -rh | head -10` for log sizes
4. `find / -type f -size +1G -exec ls -lh {} \;` for large files
5. Check logrotate status: `logrotate -d /etc/logrotate.d/[app]` | | **Resolution** | 1. **Immediate:** `sudo journalctl --vacuum-size=500M` or `truncate -s0 /var/log/[app].log`
2. Clean old logs: `find /var/log -name "*.log.*" -mtime +7 -delete`
3. Clean temp files: `sudo rm -rf /tmp/*`
4. Verify logrotate is working: `sudo logrotate -f /etc/logrotate.conf`
5. If persistent, add disk monitoring alarm at 80%
6. After mitigation, follow **R-01** before declaring resolved; retain **MITIGATING** or **MONITORING** and escalate if evidence is missing. | --- ### FM-06: TLS / Certificate Expiry | Field | Value | |-------|-------| | **Symptom** | Clients receive `certificate expired` or `x509: certificate has expired` errors | | **Likely Cause** | Auto-renewal failed, cert-manager/ACME issues, manual cert not replaced | | **Diagnosis** | 1. Check cert expiry: `echo | openssl s_client -servername [domain] -connect [domain]:443 2>/dev/null | openssl x509 -noout -dates`
2. Check cert-manager logs (if Kubernetes): `kubectl logs -n cert-manager -l app=cert-manager`
3. Check certificate resource status: `kubectl get certificate -A`
4. Verify DNS resolution for ACME challenge domain | | **Resolution** | 1. **Manual renewal:** If cert-manager: `kubectl delete certificate [name]` to trigger re-issue, or fix the ACME challenge
2. **Manual cert replacement:** Upload new cert to LB/Ingress
3. Restart ingress controller / LB after cert update
4. If auto-renewal is broken, create a ticket for the platform team
5. After mitigation, follow **R-01** before declaring resolved; retain **MITIGATING** or **MONITORING** and escalate if evidence is missing. | --- ### FM-07: Upstream API Degraded / Down | Field | Value | |-------|-------| | **Symptom** | Our service returns errors for operations that depend on [upstream], upstream latency spikes | | **Likely Cause** | Upstream outage, rate limiting, network partition | | **Diagnosis** | 1. Check upstream status page
2. Test upstream directly: `curl -v https://upstream.example.com/health`
3. Check our circuit breaker metrics
4. Check for recent upstream API changes
5. Check network connectivity: `ping`, `traceroute`, `nslookup` | | **Resolution** | 1. **If circuit breaker open:** Wait for half-open / reset, or manually reset if safe
2. **If rate limited:** Throttle requests, request quota increase
3. **If upstream outage:** Enable fallback/graceful degradation (serve stale data, queue requests)
4. Page upstream PagerDuty escalation
5. Consider feature flags to disable upstream-dependent features temporarily
6. After mitigation, follow **R-01** before declaring resolved; retain **MITIGATING** or **MONITORING** and escalate if evidence is missing. | --- ### FM-08: Slow Consumer / Queue Backlog | Field | Value | |-------|-------| | **Symptom** | Queue depth growing, consumer lag increasing, messages not processed in time | | **Likely Cause** | Consumer crashed or stuck, processing logic regression, queue partition imbalance | | **Diagnosis** | 1. Check consumer group lag (Kafka: `kafka-consumer-groups --bootstrap-server ... --group [group] --describe`)
2. Check consumer process health and logs
3. Check if messages are stuck on poison-pill messages (deserialization errors)
4. Check partition assignment and rebalance events
5. Check downstream that the consumer writes to | | **Resolution** | 1. **Restart consumers:** `kubectl rollout restart deployment/[consumer]`
2. **Skip poison-pill messages:** Seek consumer offset past bad message
3. **Scale consumers:** Increase partitions + consumer replicas
4. **If DB is bottleneck:** Investigate and resolve DB performance first
5. If backlog is critical, consider replaying messages from an earlier offset after fix
6. After mitigation, follow **R-01** before declaring resolved; retain **MITIGATING** or **MONITORING** and escalate if evidence is missing. | --- ### FM-09: DNS Resolution Failures | Field | Value | |-------|-------| | **Symptom** | `lookup [hostname]` failures, `connection refused`, intermittent timeouts | | **Likely Cause** | DNS resolver outage, cached stale records, DNS propagation delay, /etc/resolv.conf misconfiguration | | **Diagnosis** | 1. Test resolution: `dig [hostname] @[dns-server]`
2. Check `/etc/resolv.conf`
3. Check `nslookup [hostname]` and `host [hostname]`
4. Check DNS server reachability: `nc -zv [dns-server] 53`
5. Compare results across different resolvers (e.g., `8.8.8.8`) | | **Resolution** | 1. **Flush DNS cache:** `sudo systemd-resolve --flush-caches` or restart `nscd`
2. **Update resolv.conf:** Ensure valid nameservers listed
3. **Restart DNS-sidecar** (if Kubernetes with CoreDNS/node-local-dns)
4. **Override in /etc/hosts** as temporary measure
5. If using Kubernetes, check CoreDNS pods and service: `kubectl -n kube-system get pods -l k8s-app=kube-dns`
6. After mitigation, follow **R-01** before declaring resolved; retain **MITIGATING** or **MONITORING** and escalate if evidence is missing. | --- ### FM-10: Pod CrashLoopBackOff (Kubernetes) | Field | Value | |-------|-------| | **Symptom** | Pod repeatedly restarting, `CrashLoopBackOff` status, zero ready replicas | | **Likely Cause** | Startup failure (config error, missing secret, dependency unavailable), OOM, liveness probe failing | | **Diagnosis** | 1. Describe pod: `kubectl describe pod [pod-name] -n [namespace]`
2. Check pod logs: `kubectl logs [pod-name] -n [namespace] --previous`
3. Check events: `kubectl get events -n [namespace] --sort-by='.lastTimestamp'`
4. Verify configmaps/secrets are mounted: `kubectl exec -it [pod] -- cat /path/to/config`
5. Check liveness/readiness probe configuration | | **Resolution** | 1. **Fix config/secrets:** Correct the ConfigMap or Secret and re-deploy
2. **Fix missing dependency:** Start the dependency or fix the connection string
3. **Increase resources:** If OOM-killed, increase `limits.memory`
4. **Fix probe:** Correct the probe endpoint/timeout/period
5. Rollback to last known good version if config doesn't help
6. After mitigation, follow **R-01** before declaring resolved; retain **MITIGATING** or **MONITORING** and escalate if evidence is missing. | --- ## Detailed Troubleshooting Procedures > Before executing any command in these procedures that mutates production, apply the operational closure gate: verify current human authorization for the specific action and scope, record the target, affected population, maximum blast radius, success and abort/rollback criteria, rollback path, and stopping authority. These commands are examples, not permission to execute them. If the gate cannot be satisfied, stop and hand off or escalate. ### T-01: Initial Incident Triage ``` ┌──────────────────────┐ │ Alert Fires / User │ │ Reports Issue │ └──────────┬───────────┘ │ ┌──────────▼───────────┐ │ 1. ACKNOWLEDGE │ │ Ack the alert in │ │ PagerDuty/OpsGenie │ └──────────┬───────────┘ │ ┌──────────▼───────────┐ │ 2. TRIAGE │ │ - What's affected? │ │ - How many users? │ │ - Is it critical? │ │ - Create incident │ └──────────┬───────────┘ │ ┌──────────▼───────────┐ │ 3. INITIAL COMMS │ │ - Post in #incidents│ │ - Ping team channel │ │ - Update status page│ └──────────┬───────────┘ │ ┌──────────▼───────────┐ │ 4. DIAGNOSE │ │ Check dashboards, │ │ logs, traces, use │ │ Common Failure Modes│ └──────────┬───────────┘ │ ┌──────────▼───────────┐ │ 5. MITIGATE │ │ Rollback, restart, │ │ scale up, etc. │ └──────────┬───────────┘ │ ┌──────────▼───────────┐ │ 6. VERIFY │ │ Run R-01 closure │ │ evidence checks │ └──────────┬───────────┘ │ ┌──────────▼───────────┐ │ 7. RESOLVE │ │ Only after R-01 │ │ and stability │ └──────────────────────┘ ``` ### T-02: Reading Health Check Endpoints ```bash # Standard health check curl -s http://localhost:[port]/health | jq . # Verbose health check (includes dependency status) curl -s http://localhost:[port]/healthz | jq . # Readiness check (Kubernetes) curl -s http://localhost:[port]/readyz | jq . # Expected output for healthy service: # {"status":"ok","version":"1.2.3","uptime":"72h14m","dependencies":{"database":"ok","cache":"ok","queue":"degraded"}} ``` ### T-03: Capturing Diagnostic Data ```bash # Collect a diagnostics bundle ./scripts/diagnostics.sh > /tmp/diag-$(date +%s).txt # Capture thread dump (Java) jstack > /tmp/thread-dump-$(date +%s).txt # Capture heap histogram (Java) jmap -histo:live > /tmp/heap-hist-$(date +%s).txt # Capture goroutine dump (Go) curl -s http://localhost:[debug-port]/debug/pprof/goroutine?debug=2 > /tmp/goroutines.txt # Capture metrics snapshot curl -s http://localhost:[port]/metrics > /tmp/metrics-$(date +%s).txt ``` ### T-04: Safe Rollback Procedure ```bash # Step 1: Identify last known good version kubectl rollout history deployment/[deployment] -n [namespace] # Step 2: Rollback to previous revision kubectl rollout undo deployment/[deployment] -n [namespace] # Step 3: Monitor rollout status kubectl rollout status deployment/[deployment] -n [namespace] # Step 4: Start R-01 closure verification curl -s http://[service-url]/health | jq . # A health endpoint is partial evidence. Complete R-01: verify user-facing SLOs # and critical journeys, dependencies, data/state, secondary effects, and the # defined stability window and independent human confirmation before declaring the incident resolved. # Step 5: Keep the incident Mitigating or Monitoring if evidence is missing; # record the unverified boundary and hand off or escalate. # Step 6: After R-01 closure evidence and independent human confirmation are # complete, the human incident owner sends the resolution announcement. ``` --- ## Escalation Paths ### Primary Escalation | Level | Contact | Method | Response Time | |-------|---------|--------|---------------| | **L1** | On-call Engineer | PagerDuty / Phone | [15min] | | **L2** | [Team Name] Senior Engineer | PagerDuty / Slack | [30min] | | **L3** | [Team Name] Tech Lead | Phone / Slack @mention | [1hr] | | **L4** | Engineering Manager | Phone / Slack @mention | [2hr] | ### Dependency Escalation | Dependency | Team | PagerDuty Schedule | |------------|------|--------------------| | [Database Cluster] | [Data Platfom Team] | [link] | | [Kubernetes Cluster] | [Infra Team] | [link] | | [Network / DNS] | [Networking Team] | [link] | | [External API] | [Vendor Support] | [vendor-ticket-link] | ### Escalation Procedure 1. **5 minutes:** If not resolved, page L1. 2. **15 minutes:** If L1 cannot resolve, escalate to L2 (Senior Engineer). 3. **30 minutes:** If L2 needs additional context, involve L3 (Tech Lead). 4. **60 minutes:** If incident is customer-facing or SEV-1, notify L4 (Engineering Manager). 5. **SEV-1 criteria:** Service down for > 5min, data loss, security breach, revenue impact. 6. **Declare SEV-1:** Post in #severe-incidents, create incident channel, invite relevant teams. ### Communication Template ``` INCIDENT: #[incident-number] STATUS: [Investigating / Mitigating / Resolved] SERVICE: [service-name] IMPACT: [Describe user/business impact] TIMELINE: [HH:MM UTC] - Alert fired [HH:MM UTC] - On-call acknowledged [HH:MM UTC] - Rollback initiated NEXT STEPS: [What's being done] ``` --- ## Recovery Procedures ### R-01: Post-Incident Steps 1. **Verify full recovery at the user boundary** — Confirm user-facing SLOs and critical user journeys, relevant dependency health, data/state correctness, and secondary effects such as backlog recovery. Health checks, baseline error/latency, and a cleared alert are partial evidence, not a resolution verdict. 2. **Observe a stability window** — Monitor for the defined window and confirm that recovery holds without cascading or delayed effects. Record the evidence and the boundary actually exercised. 3. **Human-confirm the evidence** — A human other than the acting automation must review and confirm the complete evidence set, with the confirmation independently attributable to that person. An agent-assigned IC role, automation-authored incident record, green alert, or self-reported health check is not sufficient. 4. **Keep unresolved incidents visible** — If any required evidence or human confirmation is missing, retain the incident in **MITIGATING** or **Monitoring**, record the unverified boundary, and hand off or escalate rather than marking it resolved. 5. **Update status page** — Mark the incident as resolved if used, but only after full recovery evidence and human confirmation are complete. 6. **Resolve alert** — Close PagerDuty / OpsGenie alert after the resolution decision, not merely because the alert condition cleared. 7. **Tag, annotate, and notify** — Add incident severity, team, and service tags, then send the verified summary to the team channel and affected users. ### R-02: Data / State Recovery > **Warning:** Data recovery procedures should only be attempted by engineers with database admin access. > > Before any production restore, verify current human authorization for the specific restore and scope, record the target, affected population, maximum blast radius, success and abort/rollback criteria, rollback path, and stopping authority. Restore to staging and verify integrity first; staging evidence does not authorize the production restore. If the gate cannot be satisfied, stop and hand off or escalate rather than restoring production. ```bash # Step 1: Identify the recovery point (RPO) # Step 2: Restore from backup to a staging environment first # Step 3: Verify data integrity in staging # Step 4: Schedule maintenance window # Step 5: Perform database restore in production # Step 6: Verify application works against restored data ``` **Backup Locations:** | Resource | Backup Frequency | Retention | Restore Process | |----------|-----------------|-----------|-----------------| | [Database] | [Hourly WAL + Daily full] | [30 days] | [link to restore doc] | | [Object storage] | [Cross-region replication] | [N/A] | [link to restore doc] | | [Configuration] | [Git-controlled] | [Permanent] | Terraform apply | ### R-03: Incident Report Template ```markdown ## Post-Mortem: [Title] **Date:** [YYYY-MM-DD] **Duration:** [Start] — [End] ([X] minutes) **Severity:** [SEV-1 / SEV-2 / SEV-3] **Team:** [Team Name] ### Summary [2-3 sentence executive summary] ### Timeline - [HH:MM UTC] — [Event] - [HH:MM UTC] — [Action taken] - [HH:MM UTC] — [Recovery verified] ### Root Cause [What actually caused the incident] ### Impact - [N] requests failed - [N] users affected - [N] minutes of downtime ### Action Items | Action | Owner | Ticket | |--------|-------|--------| | [Fix root cause] | [Name] | [Jira/GH link] | | [Improve monitoring] | [Name] | [Jira/GH link] | | [Update runbook] | [Name] | [PR link] | ### Lessons Learned - What went well: - What went wrong: - What we'll do differently: ``` ### R-04: Runbook Update Checklist After any incident, update this runbook: - [ ] Add any new failure modes discovered - [ ] Update diagnosis steps that were incorrect or incomplete - [ ] Update resolution steps that worked - [ ] Update escalation paths if contacts have changed - [ ] Update links that were broken - [ ] Update SLOs / error budget if thresholds have changed - [ ] Increment version number - [ ] Update "Last Updated" date --- ## Appendix ### A — Useful Scripts & Aliases ```bash # Quick health check alias svc-health='curl -s http://localhost:[port]/health | jq .' # Check recent deploys alias svc-history='kubectl rollout history deployment/[deployment] -n [namespace]' # Tail logs alias svc-logs='kubectl logs -f deployment/[deployment] -n [namespace]' # Shell into a running pod alias svc-shell='kubectl exec -it deployment/[deployment] -n [namespace] -- /bin/bash' ``` ### B — Environment Information | Environment | URL / Access | Replicas | Instance Type | |-------------|-------------|----------|---------------| | **Production** | [prod-url] | [N] | [e.g. m5.xlarge] | | **Staging** | [staging-url] | [N] | [e.g. t3.large] | | **Development** | [dev-url] | [N] | [e.g. t3.medium] | ### C — Configuration Reference | Config Key | Description | Default | Production Value | |------------|-------------|---------|------------------| | `[DATABASE_URL]` | Primary DB connection string | — | [redacted] | | `[REDIS_URL]` | Redis connection string | — | [redacted] | | `[LOG_LEVEL]` | Logging verbosity | `info` | `info` | | `[MAX_CONNECTIONS]` | DB pool size | `10` | `[N]` | | `[REQUEST_TIMEOUT]` | Upstream request timeout | `30s` | `10s` | ### D — Related Runbooks | Runbook | Service | Link | |---------|---------|------| | [Database Runbook] | [Database] | [link] | | [Cache Runbook] | [Redis/Memcached] | [link] | | [Infrastructure Runbook] | [Kubernetes/AWS] | [link] | | [Auth Runbook] | [Auth Service] | [link] | --- > **Document Status:** This runbook is a living document. If you find errors, omissions, or out-of-date information during an incident, fix it immediately and submit a PR. > > **Template Attribution:** Based on the [Site Reliability Engineering](https://sre.google/) principles and Google's SRE books.