| name | disaster-recovery-plan |
| 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. |
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
kubectl get pods -o wide -n [namespace] | grep -v Running
kubectl get nodes -o wide | grep -v Ready
Step 2 — Assess whether auto-recovery has occurred
kubectl get pods -n [namespace] --watch
kubectl get deployment [service-name] -n [namespace]
[cloud provider CLI command to check target group health]
Step 3 — Force rescheduling if auto-recovery stalled
kubectl cordon [node-name]
kubectl drain [node-name] --ignore-daemonsets --delete-emptydir-data
kubectl get pods -o wide -n [namespace]
Step 4 — Verify service health
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]
[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)
ping [primary-region-endpoint] || echo "Primary region unreachable"
[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 \
--db-instance-identifier [dr-replica-identifier] \
--region [dr-region]
aws rds wait db-instance-available \
--db-instance-identifier [dr-replica-identifier] \
--region [dr-region]
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)
kubectl set env deployment/[service-name] \
DATABASE_URL=[new-dr-database-url] \
-n [namespace] \
--context [dr-region-context]
kubectl scale deployment/[service-name] --replicas=[N] \
-n [namespace] \
--context [dr-region-context]
kubectl get pods -n [namespace] --context [dr-region-context]
Step 5 — Cut over DNS / load balancer (5 minutes)
aws route53 change-resource-record-sets \
--hosted-zone-id [zone-id] \
--change-batch file://dr-failover-dns.json
dig [service-domain] @8.8.8.8
Step 6 — Verify end-to-end
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
[command to enable maintenance mode — e.g. kubectl set env deployment/[name] MAINTENANCE_MODE=true]
kubectl scale deployment/[service-name] --replicas=0 -n [namespace]
Step 2 — Assess scope of corruption
[SQL query to check data integrity — e.g.]
[log query to find earliest error — e.g. in Datadog:]
Step 3 — Identify the correct restore point
[command to list backups — e.g. for RDS:]
aws rds describe-db-snapshots \
--db-instance-identifier [db-identifier] \
--query 'DBSnapshots[*].[SnapshotCreateTime,DBSnapshotIdentifier]' \
--output table
Step 4 — Restore from backup
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier [service-name]-restored-[date] \
--db-snapshot-identifier [snapshot-id] \
--region [region]
aws rds wait db-instance-available \
--db-instance-identifier [service-name]-restored-[date]
aws rds describe-db-instances \
--db-instance-identifier [service-name]-restored-[date] \
--query 'DBInstances[0].Endpoint.Address'
Step 5 — Validate restored data
psql [restored-db-endpoint] -U [user] -d [database] -c "[data integrity query]"
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:
kubectl set env deployment/[service-name] [DEPENDENCY]_CIRCUIT_BREAKER=open -n [namespace]
[feature flag CLI command or dashboard link]
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
kubectl scale deployment/[service-name] --replicas=0 -n [namespace]
[command to rotate secrets — e.g. via Vault or cloud provider]
[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
[log export command — preserve evidence for forensics]
[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]
kubectl scale deployment/[service-name] --replicas=0 -n [namespace]
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;
"
psql $DATABASE_URL -c "
SELECT * FROM [table]
WHERE xmax != 0 -- recently deleted rows
LIMIT 100;
"
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)
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)
psql [test-instance-endpoint] -c "[integrity check query]"
psql [test-instance-endpoint] -c "SELECT COUNT(*) FROM [critical-table]"
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:
Failover infrastructure:
Runbooks:
Access:
Monitoring:
Quality Checks
Anti-Patterns