Automated Rollback Triggers and Runbook Integration
The operational pain this page solves is slow, manual recovery: a bad deploy ships, error rates climb, and minutes pass while someone notices the graph, finds the runbook, and manually reverts. Automated rollback closes that gap — objective signals trigger an immediate, hands-off reversal to the last known-good version, and the incident runbook is created and routed to on-call automatically so humans arrive to a contextualized incident rather than a mystery. This page covers the trigger design, the rollback action, the runbook wiring, and the safeguards that stop automated recovery from turning into a flapping loop. It complements the deployment strategies that make rollback fast in the first place.
Prerequisites
How Automated Rollback Works Under the Hood
Automated rollback is a small control loop bolted onto the end of a deploy: observe, decide, act, notify.
- Triggers. Two signal classes drive rollback. Health triggers are binary — a readiness or smoke-test failure after cutover. Metric triggers are statistical — error rate or latency breaching a threshold over a window, the same signals that gate a canary analysis. Health triggers catch hard failures instantly; metric triggers catch degradations that a health check would pass.
- The rollback action. The reversal must target a specific last known-good version, not “whatever ran before.” With blue-green it is a router flip; with a rollout it is an abort; with an immutable-release platform it is re-pointing an alias. The action is fast precisely because the target is already warm.
- Runbook integration. The moment a rollback fires, an incident is opened with the trigger, the from/to versions, and a metric snapshot, then routed to on-call. Responders start with context instead of assembling it during the outage.
- Loop safeguards. A naive “redeploy previous” can oscillate between two bad versions. Pinning the target and capping consecutive rollbacks converts a potential flap into a clean halt-and-page.
Step-by-Step Implementation
Step 1 — Record the last known-good version before deploy
# Capture the currently-serving version so rollback has a specific, warm target.
LKG=$(kubectl get deploy app -o jsonpath='{.spec.template.spec.containers[0].image}')
echo "$LKG" > .last-known-good
echo "Recorded last known-good: $LKG"Verification: .last-known-good contains the image reference currently in production, not a moving previous pointer.
Step 2 — Define the post-deploy triggers
#!/usr/bin/env bash
# scripts/rollback-triggers.sh — returns 0 (healthy) or 1 (rollback)
set -uo pipefail
URL="https://app.example.com"
# Health trigger: smoke test must pass.
curl -sf "$URL/health" | jq -e '.status == "ok"' >/dev/null || { echo "TRIGGER: health check failed"; exit 1; }
# Metric trigger: 5xx rate over the last 3 minutes must stay under 2%.
ERR=$(curl -sf "http://prometheus:9090/api/v1/query" \
--data-urlencode 'query=sum(rate(http_requests_total{app="web",code=~"5.."}[3m]))/sum(rate(http_requests_total{app="web"}[3m]))' \
| jq -r '.data.result[0].value[1] // "0"')
awk -v e="$ERR" 'BEGIN{ exit !(e > 0.02) }' && { echo "TRIGGER: error rate ${ERR} > 0.02"; exit 1; }
echo "Post-deploy signals healthy."Verification: Against a healthy deploy the script exits 0; injecting 5xx traffic makes it exit 1 with the breached value. Threshold design is expanded in wiring rollback to error-rate and latency thresholds.
Step 3 — Execute the rollback and open an incident
# .github/workflows/deploy-with-rollback.yml (rollback job)
verify-and-maybe-rollback:
needs: deploy
runs-on: ubuntu-latest
steps:
- name: Post-deploy verification
id: verify
run: bash scripts/rollback-triggers.sh
continue-on-error: true
- name: Roll back to last known-good
if: steps.verify.outcome == 'failure'
run: |
LKG=$(cat .last-known-good)
kubectl set image deploy/app app="$LKG"
kubectl rollout status deploy/app --timeout=120s
echo "Rolled back to $LKG"
- name: Open incident and page on-call
if: steps.verify.outcome == 'failure'
run: |
curl -sf -X POST https://events.pagerduty.com/v2/enqueue \
-H 'Content-Type: application/json' -d @- <<JSON
{
"routing_key": "${{ secrets.PD_ROUTING_KEY }}",
"event_action": "trigger",
"payload": {
"summary": "Auto-rollback: app deploy ${{ github.sha }} reverted",
"severity": "error",
"source": "ci-rollback",
"custom_details": { "rolled_back_to": "$(cat .last-known-good)", "commit": "${{ github.sha }}" }
}
}
JSONVerification: A forced trigger failure reverts the image and creates a PagerDuty incident whose details name the from/to versions.
Step 4 — Add loop safeguards
# scripts/loop-guard.sh — cap consecutive automated rollbacks
COUNT_FILE=.rollback-count
COUNT=$(cat "$COUNT_FILE" 2>/dev/null || echo 0)
if [ "$COUNT" -ge 2 ]; then
echo "HALT: $COUNT consecutive rollbacks — freezing deploys and paging a human."
exit 2 # a distinct code the pipeline treats as 'stop, do not retry'
fi
echo $((COUNT + 1)) > "$COUNT_FILE"Verification: After two consecutive rollbacks the guard exits 2 and the pipeline stops auto-retrying, paging instead.
Configuration Reference
| Option | Type | Default | Effect |
|---|---|---|---|
| Rollback target | enum | last-known-good SHA | Pin to a specific version, never a moving previous pointer |
| Error-rate threshold | float | 0.02 | 5xx ratio over the window that triggers rollback |
| Analysis window | duration | 3m | How long post-deploy signals are observed before deciding |
| Trigger mode | enum | automatic | Automatic for objective signals; manual approval for ambiguous ones |
| Consecutive-rollback cap | integer | 2 | Halts and pages after this many automated rollbacks |
| Incident severity | enum | error | Severity routed to the on-call escalation policy |
Integration with Upstream and Downstream Topics
Rollback is the recovery layer for the whole delivery system:
- Upstream — deployment strategy. Blue-green and canary keep a warm target that makes rollback near-instant; an aborted canary is an automated rollback.
- Upstream — feature flags. When a rolled-back version exposed a flagged feature, the flag kill switch must flip as part of the rollback action.
- Sibling — cost. Automated rollback runs deploy jobs; attribute and control that with tracking CI/CD compute costs for platform teams.
- Upstream — pipeline structure. The rollback job slots into a multi-stage pipeline as the final post-deploy gate.
Performance and Cost Impact
| Metric | Value | Notes |
|---|---|---|
| Mean time to recovery | < 2 min | Dominated by rollout-status wait; near-instant for a blue-green flip |
| Detection latency | 30 s–3 min | Set by the metric window; health failures detect immediately |
| Extra deploy jobs per incident | 1 | The rollback re-runs the deploy action against the known-good image |
| False-rollback rate | low with proper windows | Under-sized windows cause noise-driven rollbacks; see the threshold guide |
| On-call toil | near zero to recover | Humans arrive to a contextualized incident, not a manual revert |
The biggest lever on MTTR is keeping the rollback target warm — the deployment-strategy choice, not the rollback code, determines whether recovery is seconds or minutes.
Troubleshooting
Symptom: Rollback reverts to a version that is also broken
Cause: The target was “the previous deploy,” which was itself a bad release, so the rollback oscillates.
Fix: Pin the target to a specific last-known-good SHA recorded before the current deploy (Step 1), and add the consecutive-rollback cap (Step 4) so repeated failures halt rather than flap.
Symptom: Rollback fires constantly on healthy deploys
Cause: The metric window is too short or the threshold too tight, so normal traffic noise trips the trigger.
Fix: Widen the window to cover a meaningful request count and set the threshold relative to the baseline. Threshold sizing is covered in wiring rollback to error-rate and latency thresholds.
Symptom: On-call is not notified when auto-rollback fires
Cause: The incident step is gated on the wrong condition or the routing key is missing, so recovery happens silently.
Fix: Ensure the incident step shares the rollback’s if condition and that the routing key targets the correct escalation policy. Silent auto-recovery hides recurring failures.
Symptom: Health check passes but users still see errors
Cause: The health endpoint is too shallow — it returns 200 on process liveness without checking dependencies.
Fix: Make /health assert real dependencies (database and cache connectivity) and add a metric trigger so degradations that a shallow check misses still cause rollback.
Frequently Asked Questions
Should rollback be automatic or require human approval?
For objective, unambiguous signals — a failed post-deploy health check or an error-rate threshold clearly breached — rollback should be automatic, because every minute of human latency is added downtime. Reserve manual approval for ambiguous cases where reverting might be worse than holding (a data migration mid-flight, for instance). In all cases, notify on-call even when recovery is automatic, so a pattern of auto-rollbacks is visible rather than silently absorbed.
How do I prevent a rollback loop?
Two safeguards. First, pin the rollback target to a specific last-known-good version captured before the deploy, not a relative “previous deploy” that might itself be broken. Second, cap consecutive automated rollbacks (Step 4); once the cap is hit, freeze deploys and page a human instead of continuing to flap. Together these turn a potential oscillation between two bad versions into a clean stop with a human in the loop.
What belongs in a rollback runbook?
The trigger that fired (which check, what value), the versions rolled back from and to, a metric snapshot at the moment of rollback, links to the relevant logs and dashboards, and the follow-up owner. Automating the runbook’s creation — as the incident step does — means responders open the incident already holding the context they would otherwise spend the first ten minutes gathering, which is often the difference between a short blip and a prolonged outage.
Related
- Triggering Automatic Rollback on Failed Health Checks — the complete health-triggered rollback workflow.
- Wiring Rollback to Error-Rate and Latency Thresholds — designing metric thresholds that catch regressions without false alarms.
- Deployment Strategies & Progressive Delivery — the strategies that keep a warm rollback target.
- Designing Multi-Stage CI/CD Pipelines for React Apps — where the rollback job fits in the pipeline.