Disaster Recovery Plan Skill
Write a disaster recovery plan for a service or system — covering RPO/RTO targets, failure scenario runbooks, backup and restore procedures, DR testing cadence, and communication templates.
How to use it
Claude Code
- Run the line below. It pulls the whole folder into
~/.claude/skills/disaster-recovery-plan. - Describe your job in plain words. Claude Code follows the skill from there.
npx degit mohitagw15856/pm-claude-skills/skills/disaster-recovery-plan#main ~/.claude/skills/disaster-recovery-planFor one project only, change the path to .claude/skills/disaster-recovery-plan.
Claude (web or desktop app)
- On this page open ⋯ → Download .md.
- Save it as SKILL.md in a folder, zip the folder, then Customize → Skills → + → Create skill → Upload a skill.
- Pick the file and Save. Claude shows the name and description and runs a security scan.
- Check the skill is switched on.
- Start a new chat and describe your job in plain words. The AI follows the skill from there.
ChatGPT or another app
- ChatGPT: make a Project and paste it into Instructions.
- Neither? Paste it at the top of a new chat — it works for that chat.
Not working?
- Check which app you pasted it into — the steps above name the right one.
- Some skills need the paid tier of Claude or ChatGPT.
Paste into Claude, ChatGPT or Cursor.
Source of Disaster Recovery Plan Skill
Show the full text569 lines
| name | description |
|---|---|
| disaster-recovery-plan | Write a disaster recovery plan for a service or system — covering RPO/RTO targets, failure scenario runbooks, backup and restore procedures, DR testing cadence, and communication templates. Use when asked to write a DR plan, document failover procedures, create recovery runbooks, define RTO/RPO targets, or prepare for a disaster recovery game day. Produces a full DR document with per-scenario recovery runbooks, backup validation procedures, testing schedule, and communication templates. |
Disaster Recovery Plan Skill
Produce a complete disaster recovery plan for a service or system — giving engineers, SREs, and on-call responders everything they need to recover from a disaster scenario in the shortest possible time. A good DR plan is tested regularly, has exact commands (not vague instructions), and makes RTO/RPO targets measurable so the team knows whether recovery succeeded.
Required Inputs
Ask for these if not already provided:
- Service name and what it does (business function and technical role)
- Criticality tier — business impact of extended downtime (e.g. Tier 1 = revenue-critical, Tier 2 = ops impact, Tier 3 = internal only)
- Current infrastructure setup — cloud provider, regions/zones, deployment model (Kubernetes, ECS, VMs, serverless)
- RPO/RTO requirements — Recovery Point Objective (how much data loss is acceptable) and Recovery Time Objective (how long can it be down)
- Backup strategy — what is backed up, how often, where backups are stored, retention policy
- On-call contacts — names and contact details for the responder chain
Output Format
Disaster Recovery Plan: [Service Name]
Team: [Team name] | Tech lead: [Name] Criticality tier: [Tier 1 / Tier 2 / Tier 3] | Last tested: [Date] Next DR test: [Date] | Document owner: [Name] Last updated: [Date] | Review cycle: Quarterly
Emergency? Skip to Section 3 — Failure Scenario Runbooks. Find the scenario that matches your situation and follow the steps exactly.
1. Recovery Targets
| Target | Value | Rationale |
|---|---|---|
| RPO (Recovery Point Objective) | [X minutes/hours] | [e.g. "Last committed transaction — database replication is synchronous"] |
| RTO (Recovery Time Objective) | [Y minutes/hours] | [e.g. "Revenue impact begins at 30 min; target recovery in 15 min"] |
| MTTR target (non-disaster) | [Z minutes] | [Operational incidents, not DR events] |
| Data retention (backups) | [N days/weeks] | [Compliance requirement or operational policy] |
| Backup frequency | [Every X hours] | [RPO-driven — backup interval must be ≤ RPO] |
What these mean in practice:
- If a database is corrupted, we can lose at most [X minutes] of transactions before the business impact is unacceptable.
- The service must be operational again within [Y minutes/hours] of declaring a DR event.
- If either target cannot be met, escalate to [Engineering Manager] immediately.
2. Failure Scenario Inventory
| Scenario | Likelihood | Impact | RTO target | RPO target | Runbook |
|---|---|---|---|---|---|
| Single availability zone failure | Medium | [Partial / Full outage] | [15 min] | [0 — no data loss] | Section 3.1 |
| Full region failure | Low | Full outage | [60 min] | [5 min] | Section 3.2 |
| Database corruption / data loss | Low | Full outage | [90 min] | [RPO value] | Section 3.3 |
| Critical dependency outage | High | [Partial degradation] | [30 min] | [N/A] | Section 3.4 |
| Security breach / ransomware | Very low | Full outage + investigation | [4 hours] | [Last clean backup] | Section 3.5 |
| Accidental bulk data deletion | Low | Partial or full data loss | [60 min] | [RPO value] | Section 3.6 |
3. Failure Scenario Runbooks
3.1 Single Availability Zone Failure
Trigger: One AZ becomes unreachable — pods/instances in that zone stop responding.
Detection: PagerDuty alert [AlertName] fires, or cloud provider status page shows AZ degradation.
Expected RTO: [15 minutes] | Expected RPO: Zero (no data loss if multi-AZ replication is working)
Step 1 — Confirm the failure
# Check pod/instance health across zones
kubectl get pods -o wide -n [namespace] | grep -v Running
# Check which nodes are affected
kubectl get nodes -o wide | grep -v Ready
# Verify cloud provider AZ status
# AWS: https://health.aws.amazon.com/health/status
# GCP: https://status.cloud.google.com
Step 2 — Assess whether auto-recovery has occurred
# If using auto-scaling, check if replacement instances launched
kubectl get pods -n [namespace] --watch
# Check deployment replica count
kubectl get deployment [service-name] -n [namespace]
# Verify load balancer health checks are passing
[cloud provider CLI command to check target group health]
Step 3 — Force rescheduling if auto-recovery stalled
# Cordon the affected node so no new pods schedule on it
kubectl cordon [node-name]
# Drain the node — moves all pods to healthy nodes
kubectl drain [node-name] --ignore-daemonsets --delete-emptydir-data
# Verify pods have rescheduled successfully
kubectl get pods -o wide -n [namespace]
Step 4 — Verify service health
# Smoke test key endpoints
curl -s -o /dev/null -w "%{http_code}" https://[service-url]/health
curl -s -o /dev/null -w "%{http_code}" https://[service-url]/[critical-endpoint]
# Check error rate in monitoring
[dashboard link or query]
Recovery confirmed when: All pods are Running, health check returns 200, error rate is at baseline.
3.2 Full Region Failure
Trigger: The primary region is entirely unavailable. Detection: All service health checks failing, cloud provider status page confirms region-wide event. Expected RTO: [60 minutes] | Expected RPO: [5 minutes — based on cross-region replication lag]
Step 1 — Confirm regional failure (5 minutes)
# Confirm the primary region is unreachable
ping [primary-region-endpoint] || echo "Primary region unreachable"
# Check replication lag on standby region database
[command to check replica lag — e.g. for RDS: aws rds describe-db-instances --region [dr-region]]
Step 2 — Declare DR event and notify (2 minutes)
Post to #incidents:
🔴 DR EVENT — [Service Name] — Region Failure
Primary region: [region] — UNREACHABLE
Activating failover to: [dr-region]
Incident commander: [Name]
Next update: 15 minutes
Page [Engineering Manager] and [CTO/VP Eng] via PagerDuty.
Step 3 — Promote DR database (10 minutes)
# AWS RDS — promote read replica to primary
aws rds promote-read-replica \
--db-instance-identifier [dr-replica-identifier] \
--region [dr-region]
# Wait for promotion to complete
aws rds wait db-instance-available \
--db-instance-identifier [dr-replica-identifier] \
--region [dr-region]
# Record the new database endpoint
aws rds describe-db-instances \
--db-instance-identifier [dr-replica-identifier] \
--region [dr-region] \
--query 'DBInstances[0].Endpoint.Address'
Step 4 — Deploy service in DR region (20 minutes)
# Update service configuration to point at DR database
kubectl set env deployment/[service-name] \
DATABASE_URL=[new-dr-database-url] \
-n [namespace] \
--context [dr-region-context]
# Scale up the DR deployment
kubectl scale deployment/[service-name] --replicas=[N] \
-n [namespace] \
--context [dr-region-context]
# Verify all pods are running
kubectl get pods -n [namespace] --context [dr-region-context]
Step 5 — Cut over DNS / load balancer (5 minutes)
# Update DNS to point to DR region load balancer
# AWS Route 53:
aws route53 change-resource-record-sets \
--hosted-zone-id [zone-id] \
--change-batch file://dr-failover-dns.json
# Verify DNS propagation (may take up to [TTL] seconds)
dig [service-domain] @8.8.8.8
Step 6 — Verify end-to-end
# Full smoke test against DR endpoint
curl -s https://[service-url]/health
[run automated smoke test suite if available]
Recovery confirmed when: DNS resolves to DR region, smoke tests pass, error rate is at baseline.
Post-failover actions (not urgent — after service is stable):
- Do not fail back to primary until root cause is confirmed resolved
- Document data loss window (check replication lag at time of failure)
- Begin post-incident review — see [incident-postmortem skill]
3.3 Database Corruption or Data Loss
Trigger: Data in the database is corrupted, deleted, or otherwise incorrect due to a software bug, operator error, or hardware fault. Detection: Application errors referencing missing/invalid data, monitoring alerts on query error rate, user reports. Expected RTO: [90 minutes] | Expected RPO: [Backup interval — e.g. 1 hour]
Step 1 — Stop the bleeding immediately
# Put the service into maintenance mode to prevent further writes to corrupted data
[command to enable maintenance mode — e.g. kubectl set env deployment/[name] MAINTENANCE_MODE=true]
# Or: scale down the service to zero to prevent writes
kubectl scale deployment/[service-name] --replicas=0 -n [namespace]
Step 2 — Assess scope of corruption
# Identify which tables/records are affected
[SQL query to check data integrity — e.g.]
# psql $DATABASE_URL -c "SELECT COUNT(*) FROM [table] WHERE [integrity check condition]"
# Determine when corruption started (cross-reference with deploy times and error logs)
[log query to find earliest error — e.g. in Datadog:]
# service:[service-name] status:error "[corruption error message]" | sort by timestamp asc
Step 3 — Identify the correct restore point
# List available backups
[command to list backups — e.g. for RDS:]
aws rds describe-db-snapshots \
--db-instance-identifier [db-identifier] \
--query 'DBSnapshots[*].[SnapshotCreateTime,DBSnapshotIdentifier]' \
--output table
# Choose the most recent backup BEFORE corruption started
# Record the chosen snapshot ID: [snapshot-id]
Step 4 — Restore from backup
# Restore to a NEW database instance (never overwrite production directly)
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier [service-name]-restored-[date] \
--db-snapshot-identifier [snapshot-id] \
--region [region]
# Wait for restore to complete
aws rds wait db-instance-available \
--db-instance-identifier [service-name]-restored-[date]
# Get the restored instance endpoint
aws rds describe-db-instances \
--db-instance-identifier [service-name]-restored-[date] \
--query 'DBInstances[0].Endpoint.Address'
Step 5 — Validate restored data
# Connect to restored database and verify integrity
psql [restored-db-endpoint] -U [user] -d [database] -c "[data integrity query]"
# Confirm record counts match expectations
psql [restored-db-endpoint] -U [user] -d [database] -c "SELECT COUNT(*) FROM [critical-table]"
Step 6 — Point service at restored database
kubectl set env deployment/[service-name] \
DATABASE_URL=postgres://[user]:[pass]@[restored-endpoint]/[db] \
-n [namespace]
kubectl scale deployment/[service-name] --replicas=[N] -n [namespace]
Recovery confirmed when: Service is running against restored database, data integrity checks pass, error rate is at baseline.
3.4 Critical Dependency Outage
Trigger: A service that [service name] depends on is unavailable or degraded. Detection: Increased error rate or latency on endpoints that call [dependency], alerts from dependency owner. Expected RTO: Depends on dependency — [30 minutes for mitigation, resolution depends on dependency owner]
Dependency map:
| Dependency | Criticality | Degraded behaviour | Mitigation |
|---|---|---|---|
| [Database] | Critical — all writes fail | Full outage | Activate DR database (Section 3.3) |
| [Cache — Redis] | High — latency increases | Performance degradation | Bypass cache, serve from DB |
| [Auth service] | Critical — auth fails | All authenticated endpoints fail | Return cached tokens (if implemented) |
| [Message queue] | Medium — async processing delays | Writes succeed, async jobs queue | Queue backlog — see on-call runbook |
| [External API — name] | Low — feature X unavailable | Graceful degradation | Feature flag to disable feature X |
Mitigation steps:
# Enable circuit breaker / fallback for [dependency] if implemented
kubectl set env deployment/[service-name] [DEPENDENCY]_CIRCUIT_BREAKER=open -n [namespace]
# Enable feature flag to disable [dependency-backed feature]
[feature flag CLI command or dashboard link]
# Check if dependency has a status page
# [Dependency status URL]
Escalation: Contact [dependency] on-call via [PagerDuty / Slack #[channel]]. Share your service's error rate and the time dependency errors started.
3.5 Security Breach or Ransomware
Trigger: Evidence of unauthorized access, data exfiltration, or encryption of service data. Detection: Security tooling alert, unusual access patterns, user reports of data exposure. Expected RTO: [4+ hours — prioritise containment over speed] | Expected RPO: [Last verified clean backup]
Step 1 — Isolate immediately
# Take the service offline — do not attempt to recover while breach is active
kubectl scale deployment/[service-name] --replicas=0 -n [namespace]
# Revoke all API keys and service account credentials immediately
[command to rotate secrets — e.g. via Vault or cloud provider]
# Block all external access at network level
[firewall/security group command to deny all inbound traffic]
Step 2 — Notify security team immediately Page [Security lead] via PagerDuty. Do NOT attempt to remediate without security team involvement.
Post to #security-incidents (private channel, not #incidents):
🔴 SECURITY INCIDENT — [Service Name]
Time detected: [Time]
Evidence: [One sentence — what was observed]
Actions taken: Service isolated, credentials revoked
Awaiting: Security team guidance
Step 3 — Preserve evidence
# Export current logs before any remediation
[log export command — preserve evidence for forensics]
# Snapshot the current state of all infrastructure
[snapshot/image command]
Steps 4+ — Follow security team guidance. Do not restore from backup until security team confirms the attack vector is closed.
3.6 Accidental Bulk Data Deletion
Trigger: An operator, script, or application bug has deleted records in bulk. Detection: Sudden drop in record counts, user reports of missing data, application errors. Expected RTO: [60 minutes] | Expected RPO: [Backup interval]
# Step 1 — Stop further writes immediately
kubectl scale deployment/[service-name] --replicas=0 -n [namespace]
# Step 2 — Determine what was deleted and when
psql $DATABASE_URL -c "
SELECT schemaname, tablename,
n_dead_tup, last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC LIMIT 10;
"
# Step 3 — Check if deletion is recoverable via MVCC (PostgreSQL)
# Records may still be recoverable if VACUUM has not run
psql $DATABASE_URL -c "
SELECT * FROM [table]
WHERE xmax != 0 -- recently deleted rows
LIMIT 100;
"
# Step 4 — If not recoverable via MVCC, restore from backup
# Follow Section 3.3 (Database Corruption runbook) from Step 3 onward
4. Backup and Restore Procedures
Backup Configuration
| Data store | Backup type | Frequency | Retention | Location |
|---|---|---|---|---|
| [Primary database] | Automated snapshots | Every [N] hours | [N] days | [S3 bucket / cloud storage path] |
| [Primary database] | Transaction log backups | Continuous | [N] days | [Location] |
| [Secondary store — e.g. Redis] | RDB dump | Daily | [N] days | [Location] |
| [Blob/object storage] | Cross-region replication | Continuous | [N] days | [DR region bucket] |
| [Config / secrets] | Terraform state + Vault backup | On change | Indefinite | [Location] |
Backup Validation (Run Weekly)
# Test restore of latest database backup to a throwaway instance
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier [service-name]-backup-test-$(date +%Y%m%d) \
--db-snapshot-identifier $(aws rds describe-db-snapshots \
--db-instance-identifier [db-id] \
--query 'sort_by(DBSnapshots, &SnapshotCreateTime)[-1].DBSnapshotIdentifier' \
--output text)
# Wait for restore, then run integrity checks
psql [test-instance-endpoint] -c "[integrity check query]"
# Confirm row counts match recent production values (allow ≤ RPO difference)
psql [test-instance-endpoint] -c "SELECT COUNT(*) FROM [critical-table]"
# Destroy the test instance
aws rds delete-db-instance \
--db-instance-identifier [service-name]-backup-test-$(date +%Y%m%d) \
--skip-final-snapshot
5. DR Testing Cadence
Regular testing is mandatory. An untested DR plan is not a DR plan.
| Test type | Frequency | Who runs it | Pass criteria |
|---|---|---|---|
| Backup restore validation | Weekly (automated) | On-call rotation | Restore completes, integrity checks pass |
| Zone failover drill | Monthly | Engineering team | RTO target met, zero data loss |
| Region failover drill | Quarterly | Engineering + SRE | RTO/RPO targets met |
| Full DR game day | Annually | Engineering + stakeholders | All scenarios exercised, gaps documented |
| Chaos engineering (infra failures) | Weekly (automated) | Chaos engineering tooling | Service degrades gracefully, recovers automatically |
Game Day Procedure
- Pre-game day (1 week before): Notify all stakeholders, freeze production changes for the day, prepare DR environment.
- Scope definition: Choose 2–3 scenarios from Section 2. Document expected outcomes before the test.
- Execute: One person acts as incident commander, others execute runbook steps while another observes and times.
- Measure: Record actual RTO and RPO against targets for each scenario.
- Debrief (same day): Document gaps, runbook inaccuracies, and automation opportunities.
- Action items: File tickets for every gap found. Priority: P1 items must be fixed before next game day.
6. Communication Plan
Internal Communication During DR Event
Incident commander responsibilities:
- Declare the DR event and open the incident channel
- Post updates every 15 minutes minimum
- Make the call to fail over (do not let the team decide by committee)
- Notify business stakeholders of expected recovery time
Notify these people at DR event start:
| Role | Name | Contact | When to notify |
|---|---|---|---|
| Engineering manager | [Name] | [Slack / Phone] | Immediately |
| CTO / VP Engineering | [Name] | [Phone] | Tier 1 services: immediately |
| Customer success lead | [Name] | [Slack] | If customer-facing impact |
| Security lead | [Name] | [Slack / PagerDuty] | If breach suspected |
| Legal / compliance | [Name] | [Email / Phone] | If data loss involves PII |
Communication Templates
DR event declared:
🔴 DR EVENT — [Service Name]
Time: [HH:MM UTC]
Scenario: [Zone failure / Region failure / Data loss / etc.]
Impact: [Who is affected and how]
RTO target: [X minutes]
Incident commander: [Name]
War room: [Slack channel / call link]
Next update: [Time + 15 min]
Status update (every 15 minutes):
🔴 DR UPDATE — [Service Name] — [HH:MM UTC]
Status: [Investigating / Executing recovery / Verifying]
Progress: [One sentence on current step]
Blockers: [Any — or "None"]
Updated RTO estimate: [Time]
Next update: [Time + 15 min]
Recovery confirmed:
✅ DR RESOLVED — [Service Name] — [HH:MM UTC]
Total downtime: [X minutes]
Data loss: [None / X minutes of transactions]
RTO target: [X min] — Actual: [Y min] — [MET / MISSED]
RPO target: [X min] — Actual: [Y min] — [MET / MISSED]
Root cause: [One sentence]
Post-incident review: [Scheduled for / Link when created]
7. DR Readiness Checklist
Run this checklist quarterly and before any major infrastructure change:
Backups:
- Automated backups are running and alerts fire if they fail
- Most recent backup restore was tested within the last 7 days
- Backup retention meets RPO and compliance requirements
- Backups are stored in a separate region / account from primary
Failover infrastructure:
- DR region / environment exists and is provisioned (not just documented)
- DNS failover procedure is documented with exact commands
- DR database replica is current (replication lag is within RPO)
- Service can be deployed in DR region with a single command or automated pipeline
Runbooks:
- All runbooks in Section 3 have been tested within the last quarter
- Runbook commands have been verified against current infrastructure (no stale references)
- Contact list is current (no departed employees)
Access:
- On-call engineers have access to DR region console / CLI
- Service account credentials for DR region are provisioned and tested
- Break-glass accounts exist for emergency access if SSO is unavailable
Monitoring:
- Monitoring exists in DR region (not just primary)
- Alerts fire correctly when DR environment has issues
Quality Checks
- RPO and RTO targets are specific numbers, not ranges, and are agreed with the business
- Every command in every runbook has been run by a human in the last quarter — not copied from documentation untested
- DR database exists in the DR region and replication lag is monitored
- Backup restore has been tested end-to-end within the last 7 days
- The game day schedule is on the team calendar — not just documented here
- Contact list contains current phone numbers, not just Slack handles (Slack may be down during a DR event)
- Security breach runbook (3.5) explicitly names the security team contact and does not attempt self-remediation
- All thresholds (RTO/RPO) are visible in the monitoring dashboard so actual vs. target is measurable in real time
Anti-Patterns
- Do not write runbook commands without testing them — an untested command in a runbook is actively dangerous during a real disaster when cognitive load is highest
- Do not set RTO/RPO targets without business sign-off — technical teams often set aspirational targets that do not reflect actual business cost tolerance for downtime
- Do not include only the "happy path" of each failover scenario — runbooks must explicitly cover what to do when the recovery step itself fails
- Do not list Slack handles as the only escalation contact — Slack may be unavailable during a region-wide failure; phone numbers are mandatory
- Do not schedule DR game days without pre-committing to fix the gaps found — a game day that produces action items no one owns is theater, not preparedness
| 1 | |
| 2 | name disaster-recovery-plan |
| 3 | description "Write a disaster recovery plan for a service or system — covering RPO/RTO targets, failure scenario runbooks, backup and restore procedures, DR testing cadence, and communication templates. Use when asked to write a DR plan, document failover procedures, create recovery runbooks, define RTO/RPO targets, or prepare for a disaster recovery game day. Produces a full DR document with per-scenario recovery runbooks, backup validation procedures, testing schedule, and communication templates." |
| 4 | |
| 5 | |
| 6 | # Disaster Recovery Plan Skill |
| 7 | |
| 8 | Produce a complete disaster recovery plan for a service or system — giving engineers, SREs, and on-call responders everything they need to recover from a disaster scenario in the shortest possible time. A good DR plan is tested regularly, has exact commands (not vague instructions), and makes RTO/RPO targets measurable so the team knows whether recovery succeeded. |
| 9 | |
| 10 | ## Required Inputs |
| 11 | |
| 12 | Ask for these if not already provided: |
| 13 | **Service name** and what it does (business function and technical role) |
| 14 | **Criticality tier** — business impact of extended downtime (e.g. Tier 1 = revenue-critical, Tier 2 = ops impact, Tier 3 = internal only) |
| 15 | **Current infrastructure setup** — cloud provider, regions/zones, deployment model (Kubernetes, ECS, VMs, serverless) |
| 16 | **RPO/RTO requirements** — Recovery Point Objective (how much data loss is acceptable) and Recovery Time Objective (how long can it be down) |
| 17 | **Backup strategy** — what is backed up, how often, where backups are stored, retention policy |
| 18 | **On-call contacts** — names and contact details for the responder chain |
| 19 | |
| 20 | ## Output Format |
| 21 | |
| 22 | |
| 23 | |
| 24 | # Disaster Recovery Plan: [Service Name] |
| 25 | |
| 26 | **Team:** [Team name] | **Tech lead:** [Name] |
| 27 | **Criticality tier:** [Tier 1 / Tier 2 / Tier 3] | **Last tested:** [Date] |
| 28 | **Next DR test:** [Date] | **Document owner:** [Name] |
| 29 | **Last updated:** [Date] | **Review cycle:** Quarterly |
| 30 | |
| 31 | > **Emergency? Skip to Section 3 — Failure Scenario Runbooks.** Find the scenario that matches your situation and follow the steps exactly. |
| 32 | |
| 33 | |
| 34 | |
| 35 | ## 1. Recovery Targets |
| 36 | |
| 37 | | Target | Value | Rationale | |
| 38 | |---|---|---| |
| 39 | | RPO (Recovery Point Objective) | [X minutes/hours] | [e.g. "Last committed transaction — database replication is synchronous"] | |
| 40 | | RTO (Recovery Time Objective) | [Y minutes/hours] | [e.g. "Revenue impact begins at 30 min; target recovery in 15 min"] | |
| 41 | | MTTR target (non-disaster) | [Z minutes] | [Operational incidents, not DR events] | |
| 42 | | Data retention (backups) | [N days/weeks] | [Compliance requirement or operational policy] | |
| 43 | | Backup frequency | [Every X hours] | [RPO-driven — backup interval must be ≤ RPO] | |
| 44 | |
| 45 | **What these mean in practice:** |
| 46 | If a database is corrupted, we can lose at most [X minutes] of transactions before the business impact is unacceptable. |
| 47 | The service must be operational again within [Y minutes/hours] of declaring a DR event. |
| 48 | If either target cannot be met, escalate to [Engineering Manager] immediately. |
| 49 | |
| 50 | |
| 51 | |
| 52 | ## 2. Failure Scenario Inventory |
| 53 | |
| 54 | | Scenario | Likelihood | Impact | RTO target | RPO target | Runbook | |
| 55 | |---|---|---|---|---|---| |
| 56 | | Single availability zone failure | Medium | [Partial / Full outage] | [15 min] | [0 — no data loss] | Section 3.1 | |
| 57 | | Full region failure | Low | Full outage | [60 min] | [5 min] | Section 3.2 | |
| 58 | | Database corruption / data loss | Low | Full outage | [90 min] | [RPO value] | Section 3.3 | |
| 59 | | Critical dependency outage | High | [Partial degradation] | [30 min] | [N/A] | Section 3.4 | |
| 60 | | Security breach / ransomware | Very low | Full outage + investigation | [4 hours] | [Last clean backup] | Section 3.5 | |
| 61 | | Accidental bulk data deletion | Low | Partial or full data loss | [60 min] | [RPO value] | Section 3.6 | |
| 62 | |
| 63 | |
| 64 | |
| 65 | ## 3. Failure Scenario Runbooks |
| 66 | |
| 67 | ### 3.1 Single Availability Zone Failure |
| 68 | |
| 69 | **Trigger:** One AZ becomes unreachable — pods/instances in that zone stop responding. |
| 70 | **Detection:** PagerDuty alert `[AlertName]` fires, or cloud provider status page shows AZ degradation. |
| 71 | **Expected RTO:** [15 minutes] | **Expected RPO:** Zero (no data loss if multi-AZ replication is working) |
| 72 | |
| 73 | **Step 1 — Confirm the failure** |
| 74 | |
| 75 | # Check pod/instance health across zones |
| 76 | kubectl get pods -o wide -n [namespace] | grep -v Running |
| 77 | |
| 78 | # Check which nodes are affected |
| 79 | kubectl get nodes -o wide | grep -v Ready |
| 80 | |
| 81 | # Verify cloud provider AZ status |
| 82 | # AWS: https://health.aws.amazon.com/health/status |
| 83 | # GCP: https://status.cloud.google.com |
| 84 | |
| 85 | |
| 86 | **Step 2 — Assess whether auto-recovery has occurred** |
| 87 | |
| 88 | # If using auto-scaling, check if replacement instances launched |
| 89 | kubectl get pods -n [namespace] --watch |
| 90 | |
| 91 | # Check deployment replica count |
| 92 | kubectl get deployment [service-name] -n [namespace] |
| 93 | |
| 94 | # Verify load balancer health checks are passing |
| 95 | [cloud provider CLI command to check target group health] |
| 96 | |
| 97 | |
| 98 | **Step 3 — Force rescheduling if auto-recovery stalled** |
| 99 | |
| 100 | # Cordon the affected node so no new pods schedule on it |
| 101 | kubectl cordon [node-name] |
| 102 | |
| 103 | # Drain the node — moves all pods to healthy nodes |
| 104 | kubectl drain [node-name] --ignore-daemonsets --delete-emptydir-data |
| 105 | |
| 106 | # Verify pods have rescheduled successfully |
| 107 | kubectl get pods -o wide -n [namespace] |
| 108 | |
| 109 | |
| 110 | **Step 4 — Verify service health** |
| 111 | |
| 112 | # Smoke test key endpoints |
| 113 | curl -s -o /dev/null -w "%{http_code}" https://[service-url]/health |
| 114 | curl -s -o /dev/null -w "%{http_code}" https://[service-url]/[critical-endpoint] |
| 115 | |
| 116 | # Check error rate in monitoring |
| 117 | [dashboard link or query] |
| 118 | |
| 119 | |
| 120 | **Recovery confirmed when:** All pods are Running, health check returns 200, error rate is at baseline. |
| 121 | |
| 122 | |
| 123 | |
| 124 | ### 3.2 Full Region Failure |
| 125 | |
| 126 | **Trigger:** The primary region is entirely unavailable. |
| 127 | **Detection:** All service health checks failing, cloud provider status page confirms region-wide event. |
| 128 | **Expected RTO:** [60 minutes] | **Expected RPO:** [5 minutes — based on cross-region replication lag] |
| 129 | |
| 130 | **Step 1 — Confirm regional failure (5 minutes)** |
| 131 | |
| 132 | # Confirm the primary region is unreachable |
| 133 | ping [primary-region-endpoint] || echo "Primary region unreachable" |
| 134 | |
| 135 | # Check replication lag on standby region database |
| 136 | [command to check replica lag — e.g. for RDS: aws rds describe-db-instances --region [dr-region]] |
| 137 | |
| 138 | |
| 139 | **Step 2 — Declare DR event and notify (2 minutes)** |
| 140 | |
| 141 | Post to `#incidents`: |
| 142 | |
| 143 | 🔴 DR EVENT — [Service Name] — Region Failure |
| 144 | Primary region: [region] — UNREACHABLE |
| 145 | Activating failover to: [dr-region] |
| 146 | Incident commander: [Name] |
| 147 | Next update: 15 minutes |
| 148 | |
| 149 | |
| 150 | Page [Engineering Manager] and [CTO/VP Eng] via PagerDuty. |
| 151 | |
| 152 | **Step 3 — Promote DR database (10 minutes)** |
| 153 | |
| 154 | # AWS RDS — promote read replica to primary |
| 155 | aws rds promote-read-replica \ |
| 156 | --db-instance-identifier [dr-replica-identifier] \ |
| 157 | --region [dr-region] |
| 158 | |
| 159 | # Wait for promotion to complete |
| 160 | aws rds wait db-instance-available \ |
| 161 | --db-instance-identifier [dr-replica-identifier] \ |
| 162 | --region [dr-region] |
| 163 | |
| 164 | # Record the new database endpoint |
| 165 | aws rds describe-db-instances \ |
| 166 | --db-instance-identifier [dr-replica-identifier] \ |
| 167 | --region [dr-region] \ |
| 168 | --query 'DBInstances[0].Endpoint.Address' |
| 169 | |
| 170 | |
| 171 | **Step 4 — Deploy service in DR region (20 minutes)** |
| 172 | |
| 173 | # Update service configuration to point at DR database |
| 174 | kubectl set env deployment/[service-name] \ |
| 175 | DATABASE_URL=[new-dr-database-url] \ |
| 176 | -n [namespace] \ |
| 177 | --context [dr-region-context] |
| 178 | |
| 179 | # Scale up the DR deployment |
| 180 | kubectl scale deployment/[service-name] --replicas=[N] \ |
| 181 | -n [namespace] \ |
| 182 | --context [dr-region-context] |
| 183 | |
| 184 | # Verify all pods are running |
| 185 | kubectl get pods -n [namespace] --context [dr-region-context] |
| 186 | |
| 187 | |
| 188 | **Step 5 — Cut over DNS / load balancer (5 minutes)** |
| 189 | |
| 190 | # Update DNS to point to DR region load balancer |
| 191 | # AWS Route 53: |
| 192 | aws route53 change-resource-record-sets \ |
| 193 | --hosted-zone-id [zone-id] \ |
| 194 | --change-batch file://dr-failover-dns.json |
| 195 | |
| 196 | # Verify DNS propagation (may take up to [TTL] seconds) |
| 197 | dig [service-domain] @8.8.8.8 |
| 198 | |
| 199 | |
| 200 | **Step 6 — Verify end-to-end** |
| 201 | |
| 202 | # Full smoke test against DR endpoint |
| 203 | curl -s https://[service-url]/health |
| 204 | [run automated smoke test suite if available] |
| 205 | |
| 206 | |
| 207 | **Recovery confirmed when:** DNS resolves to DR region, smoke tests pass, error rate is at baseline. |
| 208 | |
| 209 | **Post-failover actions (not urgent — after service is stable):** |
| 210 | Do not fail back to primary until root cause is confirmed resolved |
| 211 | Document data loss window (check replication lag at time of failure) |
| 212 | Begin post-incident review — see [incident-postmortem skill] |
| 213 | |
| 214 | |
| 215 | |
| 216 | ### 3.3 Database Corruption or Data Loss |
| 217 | |
| 218 | **Trigger:** Data in the database is corrupted, deleted, or otherwise incorrect due to a software bug, operator error, or hardware fault. |
| 219 | **Detection:** Application errors referencing missing/invalid data, monitoring alerts on query error rate, user reports. |
| 220 | **Expected RTO:** [90 minutes] | **Expected RPO:** [Backup interval — e.g. 1 hour] |
| 221 | |
| 222 | **Step 1 — Stop the bleeding immediately** |
| 223 | |
| 224 | # Put the service into maintenance mode to prevent further writes to corrupted data |
| 225 | [command to enable maintenance mode — e.g. kubectl set env deployment/[name] MAINTENANCE_MODE=true] |
| 226 | |
| 227 | # Or: scale down the service to zero to prevent writes |
| 228 | kubectl scale deployment/[service-name] --replicas=0 -n [namespace] |
| 229 | |
| 230 | |
| 231 | **Step 2 — Assess scope of corruption** |
| 232 | |
| 233 | # Identify which tables/records are affected |
| 234 | [SQL query to check data integrity — e.g.] |
| 235 | # psql $DATABASE_URL -c "SELECT COUNT(*) FROM [table] WHERE [integrity check condition]" |
| 236 | |
| 237 | # Determine when corruption started (cross-reference with deploy times and error logs) |
| 238 | [log query to find earliest error — e.g. in Datadog:] |
| 239 | # service:[service-name] status:error "[corruption error message]" | sort by timestamp asc |
| 240 | |
| 241 | |
| 242 | **Step 3 — Identify the correct restore point** |
| 243 | |
| 244 | # List available backups |
| 245 | [command to list backups — e.g. for RDS:] |
| 246 | aws rds describe-db-snapshots \ |
| 247 | --db-instance-identifier [db-identifier] \ |
| 248 | --query 'DBSnapshots[*].[SnapshotCreateTime,DBSnapshotIdentifier]' \ |
| 249 | --output table |
| 250 | |
| 251 | # Choose the most recent backup BEFORE corruption started |
| 252 | # Record the chosen snapshot ID: [snapshot-id] |
| 253 | |
| 254 | |
| 255 | **Step 4 — Restore from backup** |
| 256 | |
| 257 | # Restore to a NEW database instance (never overwrite production directly) |
| 258 | aws rds restore-db-instance-from-db-snapshot \ |
| 259 | --db-instance-identifier [service-name]-restored-[date] \ |
| 260 | --db-snapshot-identifier [snapshot-id] \ |
| 261 | --region [region] |
| 262 | |
| 263 | # Wait for restore to complete |
| 264 | aws rds wait db-instance-available \ |
| 265 | --db-instance-identifier [service-name]-restored-[date] |
| 266 | |
| 267 | # Get the restored instance endpoint |
| 268 | aws rds describe-db-instances \ |
| 269 | --db-instance-identifier [service-name]-restored-[date] \ |
| 270 | --query 'DBInstances[0].Endpoint.Address' |
| 271 | |
| 272 | |
| 273 | **Step 5 — Validate restored data** |
| 274 | |
| 275 | # Connect to restored database and verify integrity |
| 276 | psql [restored-db-endpoint] -U [user] -d [database] -c "[data integrity query]" |
| 277 | |
| 278 | # Confirm record counts match expectations |
| 279 | psql [restored-db-endpoint] -U [user] -d [database] -c "SELECT COUNT(*) FROM [critical-table]" |
| 280 | |
| 281 | |
| 282 | **Step 6 — Point service at restored database** |
| 283 | |
| 284 | kubectl set env deployment/[service-name] \ |
| 285 | DATABASE_URL=postgres://[user]:[pass]@[restored-endpoint]/[db] \ |
| 286 | -n [namespace] |
| 287 | |
| 288 | kubectl scale deployment/[service-name] --replicas=[N] -n [namespace] |
| 289 | |
| 290 | |
| 291 | **Recovery confirmed when:** Service is running against restored database, data integrity checks pass, error rate is at baseline. |
| 292 | |
| 293 | |
| 294 | |
| 295 | ### 3.4 Critical Dependency Outage |
| 296 | |
| 297 | **Trigger:** A service that [service name] depends on is unavailable or degraded. |
| 298 | **Detection:** Increased error rate or latency on endpoints that call [dependency], alerts from dependency owner. |
| 299 | **Expected RTO:** Depends on dependency — [30 minutes for mitigation, resolution depends on dependency owner] |
| 300 | |
| 301 | **Dependency map:** |
| 302 | |
| 303 | | Dependency | Criticality | Degraded behaviour | Mitigation | |
| 304 | |---|---|---|---| |
| 305 | | [Database] | Critical — all writes fail | Full outage | Activate DR database (Section 3.3) | |
| 306 | | [Cache — Redis] | High — latency increases | Performance degradation | Bypass cache, serve from DB | |
| 307 | | [Auth service] | Critical — auth fails | All authenticated endpoints fail | Return cached tokens (if implemented) | |
| 308 | | [Message queue] | Medium — async processing delays | Writes succeed, async jobs queue | Queue backlog — see on-call runbook | |
| 309 | | [External API — name] | Low — feature X unavailable | Graceful degradation | Feature flag to disable feature X | |
| 310 | |
| 311 | **Mitigation steps:** |
| 312 | |
| 313 | # Enable circuit breaker / fallback for [dependency] if implemented |
| 314 | kubectl set env deployment/[service-name] [DEPENDENCY]_CIRCUIT_BREAKER=open -n [namespace] |
| 315 | |
| 316 | # Enable feature flag to disable [dependency-backed feature] |
| 317 | [feature flag CLI command or dashboard link] |
| 318 | |
| 319 | # Check if dependency has a status page |
| 320 | # [Dependency status URL] |
| 321 | |
| 322 | |
| 323 | **Escalation:** Contact [dependency] on-call via [PagerDuty / Slack `#[channel]`]. Share your service's error rate and the time dependency errors started. |
| 324 | |
| 325 | |
| 326 | |
| 327 | ### 3.5 Security Breach or Ransomware |
| 328 | |
| 329 | **Trigger:** Evidence of unauthorized access, data exfiltration, or encryption of service data. |
| 330 | **Detection:** Security tooling alert, unusual access patterns, user reports of data exposure. |
| 331 | **Expected RTO:** [4+ hours — prioritise containment over speed] | **Expected RPO:** [Last verified clean backup] |
| 332 | |
| 333 | **Step 1 — Isolate immediately** |
| 334 | |
| 335 | # Take the service offline — do not attempt to recover while breach is active |
| 336 | kubectl scale deployment/[service-name] --replicas=0 -n [namespace] |
| 337 | |
| 338 | # Revoke all API keys and service account credentials immediately |
| 339 | [command to rotate secrets — e.g. via Vault or cloud provider] |
| 340 | |
| 341 | # Block all external access at network level |
| 342 | [firewall/security group command to deny all inbound traffic] |
| 343 | |
| 344 | |
| 345 | **Step 2 — Notify security team immediately** |
| 346 | Page [Security lead] via PagerDuty. Do NOT attempt to remediate without security team involvement. |
| 347 | |
| 348 | Post to `#security-incidents` (private channel, not `#incidents`): |
| 349 | |
| 350 | 🔴 SECURITY INCIDENT — [Service Name] |
| 351 | Time detected: [Time] |
| 352 | Evidence: [One sentence — what was observed] |
| 353 | Actions taken: Service isolated, credentials revoked |
| 354 | Awaiting: Security team guidance |
| 355 | |
| 356 | |
| 357 | **Step 3 — Preserve evidence** |
| 358 | |
| 359 | # Export current logs before any remediation |
| 360 | [log export command — preserve evidence for forensics] |
| 361 | |
| 362 | # Snapshot the current state of all infrastructure |
| 363 | [snapshot/image command] |
| 364 | |
| 365 | |
| 366 | **Steps 4+ — Follow security team guidance.** Do not restore from backup until security team confirms the attack vector is closed. |
| 367 | |
| 368 | |
| 369 | |
| 370 | ### 3.6 Accidental Bulk Data Deletion |
| 371 | |
| 372 | **Trigger:** An operator, script, or application bug has deleted records in bulk. |
| 373 | **Detection:** Sudden drop in record counts, user reports of missing data, application errors. |
| 374 | **Expected RTO:** [60 minutes] | **Expected RPO:** [Backup interval] |
| 375 | |
| 376 | |
| 377 | # Step 1 — Stop further writes immediately |
| 378 | kubectl scale deployment/[service-name] --replicas=0 -n [namespace] |
| 379 | |
| 380 | # Step 2 — Determine what was deleted and when |
| 381 | psql $DATABASE_URL -c " |
| 382 | SELECT schemaname, tablename, |
| 383 | n_dead_tup, last_autovacuum |
| 384 | FROM pg_stat_user_tables |
| 385 | ORDER BY n_dead_tup DESC LIMIT 10; |
| 386 | " |
| 387 | |
| 388 | # Step 3 — Check if deletion is recoverable via MVCC (PostgreSQL) |
| 389 | # Records may still be recoverable if VACUUM has not run |
| 390 | psql $DATABASE_URL -c " |
| 391 | SELECT * FROM [table] |
| 392 | WHERE xmax != 0 -- recently deleted rows |
| 393 | LIMIT 100; |
| 394 | " |
| 395 | |
| 396 | # Step 4 — If not recoverable via MVCC, restore from backup |
| 397 | # Follow Section 3.3 (Database Corruption runbook) from Step 3 onward |
| 398 | |
| 399 | |
| 400 | |
| 401 | |
| 402 | ## 4. Backup and Restore Procedures |
| 403 | |
| 404 | ### Backup Configuration |
| 405 | |
| 406 | | Data store | Backup type | Frequency | Retention | Location | |
| 407 | |---|---|---|---|---| |
| 408 | | [Primary database] | Automated snapshots | Every [N] hours | [N] days | [S3 bucket / cloud storage path] | |
| 409 | | [Primary database] | Transaction log backups | Continuous | [N] days | [Location] | |
| 410 | | [Secondary store — e.g. Redis] | RDB dump | Daily | [N] days | [Location] | |
| 411 | | [Blob/object storage] | Cross-region replication | Continuous | [N] days | [DR region bucket] | |
| 412 | | [Config / secrets] | Terraform state + Vault backup | On change | Indefinite | [Location] | |
| 413 | |
| 414 | ### Backup Validation (Run Weekly) |
| 415 | |
| 416 | |
| 417 | # Test restore of latest database backup to a throwaway instance |
| 418 | aws rds restore-db-instance-from-db-snapshot \ |
| 419 | --db-instance-identifier [service-name]-backup-test-$(date +%Y%m%d) \ |
| 420 | --db-snapshot-identifier $(aws rds describe-db-snapshots \ |
| 421 | --db-instance-identifier [db-id] \ |
| 422 | --query 'sort_by(DBSnapshots, &SnapshotCreateTime)[-1].DBSnapshotIdentifier' \ |
| 423 | --output text) |
| 424 | |
| 425 | # Wait for restore, then run integrity checks |
| 426 | psql [test-instance-endpoint] -c "[integrity check query]" |
| 427 | |
| 428 | # Confirm row counts match recent production values (allow ≤ RPO difference) |
| 429 | psql [test-instance-endpoint] -c "SELECT COUNT(*) FROM [critical-table]" |
| 430 | |
| 431 | # Destroy the test instance |
| 432 | aws rds delete-db-instance \ |
| 433 | --db-instance-identifier [service-name]-backup-test-$(date +%Y%m%d) \ |
| 434 | --skip-final-snapshot |
| 435 | |
| 436 | |
| 437 | |
| 438 | |
| 439 | ## 5. DR Testing Cadence |
| 440 | |
| 441 | Regular testing is mandatory. An untested DR plan is not a DR plan. |
| 442 | |
| 443 | | Test type | Frequency | Who runs it | Pass criteria | |
| 444 | |---|---|---|---| |
| 445 | | Backup restore validation | Weekly (automated) | On-call rotation | Restore completes, integrity checks pass | |
| 446 | | Zone failover drill | Monthly | Engineering team | RTO target met, zero data loss | |
| 447 | | Region failover drill | Quarterly | Engineering + SRE | RTO/RPO targets met | |
| 448 | | Full DR game day | Annually | Engineering + stakeholders | All scenarios exercised, gaps documented | |
| 449 | | Chaos engineering (infra failures) | Weekly (automated) | Chaos engineering tooling | Service degrades gracefully, recovers automatically | |
| 450 | |
| 451 | ### Game Day Procedure |
| 452 | |
| 453 | **Pre-game day (1 week before):** Notify all stakeholders, freeze production changes for the day, prepare DR environment. |
| 454 | **Scope definition:** Choose 2–3 scenarios from Section 2. Document expected outcomes before the test. |
| 455 | **Execute:** One person acts as incident commander, others execute runbook steps while another observes and times. |
| 456 | **Measure:** Record actual RTO and RPO against targets for each scenario. |
| 457 | **Debrief (same day):** Document gaps, runbook inaccuracies, and automation opportunities. |
| 458 | **Action items:** File tickets for every gap found. Priority: P1 items must be fixed before next game day. |
| 459 | |
| 460 | |
| 461 | |
| 462 | ## 6. Communication Plan |
| 463 | |
| 464 | ### Internal Communication During DR Event |
| 465 | |
| 466 | **Incident commander responsibilities:** |
| 467 | Declare the DR event and open the incident channel |
| 468 | Post updates every 15 minutes minimum |
| 469 | Make the call to fail over (do not let the team decide by committee) |
| 470 | Notify business stakeholders of expected recovery time |
| 471 | |
| 472 | **Notify these people at DR event start:** |
| 473 | |
| 474 | | Role | Name | Contact | When to notify | |
| 475 | |---|---|---|---| |
| 476 | | Engineering manager | [Name] | [Slack / Phone] | Immediately | |
| 477 | | CTO / VP Engineering | [Name] | [Phone] | Tier 1 services: immediately | |
| 478 | | Customer success lead | [Name] | [Slack] | If customer-facing impact | |
| 479 | | Security lead | [Name] | [Slack / PagerDuty] | If breach suspected | |
| 480 | | Legal / compliance | [Name] | [Email / Phone] | If data loss involves PII | |
| 481 | |
| 482 | ### Communication Templates |
| 483 | |
| 484 | **DR event declared:** |
| 485 | |
| 486 | 🔴 DR EVENT — [Service Name] |
| 487 | Time: [HH:MM UTC] |
| 488 | Scenario: [Zone failure / Region failure / Data loss / etc.] |
| 489 | Impact: [Who is affected and how] |
| 490 | RTO target: [X minutes] |
| 491 | Incident commander: [Name] |
| 492 | War room: [Slack channel / call link] |
| 493 | Next update: [Time + 15 min] |
| 494 | |
| 495 | |
| 496 | **Status update (every 15 minutes):** |
| 497 | |
| 498 | 🔴 DR UPDATE — [Service Name] — [HH:MM UTC] |
| 499 | Status: [Investigating / Executing recovery / Verifying] |
| 500 | Progress: [One sentence on current step] |
| 501 | Blockers: [Any — or "None"] |
| 502 | Updated RTO estimate: [Time] |
| 503 | Next update: [Time + 15 min] |
| 504 | |
| 505 | |
| 506 | **Recovery confirmed:** |
| 507 | |
| 508 | ✅ DR RESOLVED — [Service Name] — [HH:MM UTC] |
| 509 | Total downtime: [X minutes] |
| 510 | Data loss: [None / X minutes of transactions] |
| 511 | RTO target: [X min] — Actual: [Y min] — [MET / MISSED] |
| 512 | RPO target: [X min] — Actual: [Y min] — [MET / MISSED] |
| 513 | Root cause: [One sentence] |
| 514 | Post-incident review: [Scheduled for / Link when created] |
| 515 | |
| 516 | |
| 517 | |
| 518 | |
| 519 | ## 7. DR Readiness Checklist |
| 520 | |
| 521 | Run this checklist quarterly and before any major infrastructure change: |
| 522 | |
| 523 | **Backups:** |
| 524 | [ ] Automated backups are running and alerts fire if they fail |
| 525 | [ ] Most recent backup restore was tested within the last 7 days |
| 526 | [ ] Backup retention meets RPO and compliance requirements |
| 527 | [ ] Backups are stored in a separate region / account from primary |
| 528 | |
| 529 | **Failover infrastructure:** |
| 530 | [ ] DR region / environment exists and is provisioned (not just documented) |
| 531 | [ ] DNS failover procedure is documented with exact commands |
| 532 | [ ] DR database replica is current (replication lag is within RPO) |
| 533 | [ ] Service can be deployed in DR region with a single command or automated pipeline |
| 534 | |
| 535 | **Runbooks:** |
| 536 | [ ] All runbooks in Section 3 have been tested within the last quarter |
| 537 | [ ] Runbook commands have been verified against current infrastructure (no stale references) |
| 538 | [ ] Contact list is current (no departed employees) |
| 539 | |
| 540 | **Access:** |
| 541 | [ ] On-call engineers have access to DR region console / CLI |
| 542 | [ ] Service account credentials for DR region are provisioned and tested |
| 543 | [ ] Break-glass accounts exist for emergency access if SSO is unavailable |
| 544 | |
| 545 | **Monitoring:** |
| 546 | [ ] Monitoring exists in DR region (not just primary) |
| 547 | [ ] Alerts fire correctly when DR environment has issues |
| 548 | |
| 549 | |
| 550 | |
| 551 | ## Quality Checks |
| 552 | |
| 553 | [ ] RPO and RTO targets are specific numbers, not ranges, and are agreed with the business |
| 554 | [ ] Every command in every runbook has been run by a human in the last quarter — not copied from documentation untested |
| 555 | [ ] DR database exists in the DR region and replication lag is monitored |
| 556 | [ ] Backup restore has been tested end-to-end within the last 7 days |
| 557 | [ ] The game day schedule is on the team calendar — not just documented here |
| 558 | [ ] Contact list contains current phone numbers, not just Slack handles (Slack may be down during a DR event) |
| 559 | [ ] Security breach runbook (3.5) explicitly names the security team contact and does not attempt self-remediation |
| 560 | [ ] All thresholds (RTO/RPO) are visible in the monitoring dashboard so actual vs. target is measurable in real time |
| 561 | |
| 562 | ## Anti-Patterns |
| 563 | |
| 564 | [ ] Do not write runbook commands without testing them — an untested command in a runbook is actively dangerous during a real disaster when cognitive load is highest |
| 565 | [ ] Do not set RTO/RPO targets without business sign-off — technical teams often set aspirational targets that do not reflect actual business cost tolerance for downtime |
| 566 | [ ] Do not include only the "happy path" of each failover scenario — runbooks must explicitly cover what to do when the recovery step itself fails |
| 567 | [ ] Do not list Slack handles as the only escalation contact — Slack may be unavailable during a region-wide failure; phone numbers are mandatory |
| 568 | [ ] Do not schedule DR game days without pre-committing to fix the gaps found — a game day that produces action items no one owns is theater, not preparedness |
| 569 |
Discussion
Browse more free Claude skills or everything in Development.


