Safe Deployment and Rollback Strategies Questions
Releasing changes to production safely and incrementally, and recovering when they fail: blue-green, canary, and rolling deployments, feature flags, dark launches, traffic shifting, and progressive rollout, together with rollback strategies, safe-deploy practices, blast-radius containment, automated recovery, and safe forward/backward migration. Covers deployment orchestration across cloud platforms, staged exposure of new behavior to users, assessing deployment risk, designing reversible releases, and restoring a known-good state quickly. Focuses on how a release reaches production and how it is unwound on failure, distinct from broader incident command, which lives in Enterprise Operations & Incident Management.
Propose a rollout strategy for a stateful service, such as a Redis cluster, that needs a version upgrade without data loss: coordination, backup, and failover.
Sample Answer
Direct answer
Upgrading a stateful service like a Redis cluster without data loss means treating the upgrade as a carefully sequenced, node-by-node operation with a verified backup as the safety net, never a wholesale replace-everything-at-once approach, since a stateful cluster's whole value is the data it's currently holding, which a naive rollout could easily lose.
Structured elaboration
- Backup first, always: before touching anything, a verified (not just taken, but confirmed restorable) backup or snapshot of the current cluster state, so there's a fallback that doesn't depend on the upgrade or rollback mechanism working correctly.
- Understand the cluster's replication/failover topology: for Redis specifically, a cluster typically has primary and replica nodes; the upgrade sequence should upgrade REPLICAS first (since losing a replica temporarily doesn't lose data or availability, the primary is still serving), then trigger a controlled failover to an already-upgraded replica (promoting it to primary), THEN upgrade the now-demoted former primary as the last node.
- Coordination during the failover step specifically: a controlled failover (not a crash-triggered one) briefly pauses writes or redirects them, depending on the client library's failover handling, so this moment needs its own testing and a defined acceptable interruption window, since it's the one point in the sequence where a genuine, if brief, disruption is likely.
- Verify data consistency after each node's upgrade, not just at the end: confirming a freshly-upgraded replica has caught up and is correctly replicating before proceeding to the next step, rather than assuming replication "worked" without checking.
- Rollback path if something goes wrong mid-sequence: since nodes are upgraded one at a time, a problem discovered on an upgraded replica can be handled by NOT promoting it (avoiding it becoming primary) and instead restoring it from the still-healthy cluster's current replication state, or from the verified backup if the cluster itself is compromised, without needing to touch the nodes not yet upgraded.
Worked example
A 3-node Redis cluster (1 primary, 2 replicas): upgrade replica A first, verify it's caught up and serving correctly, upgrade replica B, verify the same, then trigger a controlled failover promoting one of the now-upgraded replicas to primary, verify the new primary is stable, and finally upgrade the former primary (now a replica). Throughout, a pre-upgrade backup exists as the ultimate fallback if something goes wrong that node-by-node rollback alone can't cleanly fix.
Trade-offs and pitfalls
This sequential, verify-at-each-step approach is meaningfully slower than a bulk replace-all-at-once upgrade, but the bulk approach risks momentarily having no healthy, upgraded node capable of correctly serving if something goes wrong mid-upgrade across multiple nodes simultaneously, a much worse failure mode for a stateful cluster than for stateless compute. The common mistake is treating a stateful cluster's upgrade like a stateless rolling update (just replace instances gradually) without accounting for the coordination REPLICATION and FAILOVER require, which stateless services simply don't have.
Design a feature-flag system: storage, low-latency evaluation SDKs, targeting by cohort/region/percentage, an audit trail, and a kill-switch. How do you guarantee safety when a flag controls something business-critical?
Sample Answer
Direct answer
A feature-flag system needs a storage layer for flag state, a low-latency SDK that evaluates flags in the request path without adding meaningful delay, targeting rules that support cohort/region/percentage-based exposure, and an audit trail plus a kill-switch, all built around the principle that evaluating a flag should never be slower or less reliable than the code path it's gating.
Structured elaboration
- Storage: a small, purpose-built store (not the main application database, to avoid coupling flag-read latency and availability to unrelated app load) holding flag definitions, targeting rules, and current values; it needs to support fast reads far more than fast writes, since evaluation happens on every relevant request while flag CHANGES happen rarely by comparison.
- Low-latency evaluation: the SDK should evaluate flags from a LOCAL, in-memory copy of the flag configuration (updated via a background poll or a streaming push), never a live network call per request, since a per-request network call to a flag service would add latency and a new failure mode to every gated code path.
- Targeting: percentage rollouts (typically implemented as a deterministic hash of a stable user identifier into a bucket, so the same user consistently gets the same treatment across requests), cohort targeting (by user attribute), and region targeting, composable so a flag can express "10% of beta users in region X."
- Audit trail: every flag change (who, when, old value, new value) logged immutably, both for debugging ("did this incident start right after someone flipped a flag?") and for compliance in regulated environments.
- Kill-switch: a flag category with the fastest possible propagation path and the simplest possible evaluation logic (no complex targeting rules to evaluate, just on/off), since a kill-switch's whole value proposition is speed and reliability under exactly the conditions (an active incident) where the rest of the system might be under stress.
- Guaranteeing safety when a flag controls something critical: a hard-coded, safe fallback value baked into the SDK for when the flag service is unreachable (never silently defaulting to "on" for something risky), strict typing/validation on flag values so a malformed update can't be evaluated as truthy by accident, and access control on WHO can flip a critical flag, distinct from who can flip a low-stakes experiment flag.
Worked example
flowchart LR
A[Flag Admin UI] -->|writes rule| B[(Flag Config Store)]
B -->|streams update| C[SDK: in-memory cache]
D[Application request] --> C
C -->|evaluates locally, no network call| D
B -->|every change| E[(Audit Log)]
A percentage rollout flag targeting "10% of users in region EU" evaluates by hashing the user's stable ID plus the flag's own key into a bucket 0-99, comparing against the 10% threshold; using the FLAG'S key as part of the hash input (not just the user ID alone) means two different flags targeting the same user independently land in different, uncorrelated buckets, avoiding a situation where the same 10% of users always happens to be the first exposed to every new flag.
Trade-offs and pitfalls
The single biggest risk in a homegrown flag system is the evaluation path becoming a dependency the application can't function without; if the SDK's local cache and fallback logic aren't solid, a flag-service outage becomes an application outage, which is precisely backward from what a safety mechanism is supposed to do. Convincing security/compliance teams to trust the system usually comes down to demonstrating the audit trail's completeness and the access-control model's rigor for critical flags specifically, not the system's feature richness.
You're performing a blue-green cutover behind a global CDN. How do you switch traffic without serving stale content or poisoning the cache, and what would you check before and after the switch?
Sample Answer
Direct answer
Switching traffic during a blue-green cutover behind a global CDN needs to account for the CDN's OWN cache, which is a separate layer from the origin switch itself: flipping which origin serves requests doesn't automatically clear what the CDN has already cached from the old origin, so you need to explicitly invalidate stale cached content at the moment of cutover, or users can keep seeing old, cached responses even though the origin has switched.
Structured elaboration
- Warm the new origin's cache before cutover: if the CDN caches per-origin, priming commonly-requested paths against the green origin before it starts receiving real traffic avoids a cold-cache latency spike at the moment of cutover.
- CDN invalidation at cutover: for content that's origin-dependent (a page whose HTML or API response differs between blue and green), explicitly purge/invalidate the relevant cache keys at the CDN as part of the cutover step, not after, or users could be served a mix of old cached content and new origin responses inconsistently.
- DNS TTL for the origin switch itself: if the CDN's origin selection is driven by DNS, a short TTL for the cutover window ensures the CDN's edge nodes pick up the new origin promptly; a long, stale TTL from routine operation can mean some edge locations keep hitting the old origin well past when you believe the cutover completed.
- Session affinity: for anything relying on sticky sessions at the CDN or origin level, a user mid-session during cutover could have their session pinned to the OLD origin depending on how affinity is implemented; confirm whether session state is externalized (shared between blue and green) or whether affinity itself needs to be reset as part of cutover.
- What to check before the switch: the green origin is warm and passing health checks directly (bypassing the CDN, hitting it straight) so you're validating the origin itself, not a cached response. What to check after: sample real, CDN-fronted requests from multiple edge locations/regions to confirm they're actually hitting the new origin and getting fresh (not stale-cached) responses, since a purely origin-side health check wouldn't catch a CDN-layer caching problem.
Worked example
A cutover where the green origin's health check passes cleanly directly against the origin, but samples of CDN-fronted requests from three different edge regions ten minutes post-cutover show one region still serving a stale cached response, tracing back to a CDN edge node that hadn't yet honored the DNS TTL change. This is caught specifically by testing THROUGH the CDN from multiple locations, not just testing the origin directly, which is exactly why a pure origin health check isn't sufficient validation for a CDN-fronted cutover.
Trade-offs and pitfalls
The most common mistake is validating only the origin directly and declaring the cutover successful, missing that the CDN layer between users and the origin has its own state (cached content, possibly stale DNS resolution at the edge) that needs its own explicit verification. Aggressive cache invalidation at cutover trades a brief spike in origin load (as the CDN re-fetches everything fresh) for correctness; under-invalidating trades correctness for a smoother load profile, and getting that balance wrong in either direction has a real cost.
Describe how GitOps changes the rollback model compared to imperative CI/CD. Explain concrete steps to revert a bad deployment using a GitOps workflow (for example ArgoCD or Flux) and how you ensure the cluster reconciles to the reverted state safely.
Sample Answer
Direct answer
Imperative CI/CD's rollback model is "run the DEPLOY step again with the previous artifact," a forward-facing operation on the deployment TOOL; GitOps's rollback model is "make Git say what it said before," a backward-facing operation on the SOURCE OF TRUTH, and the deployment mechanism (the reconciler) then does exactly what it always does, reconcile the cluster toward whatever Git currently declares. This is a genuine model shift, not just a different command: in GitOps, there is no separate "rollback" code path at all, reverting IS just another declarative change, going through the identical PR-and-reconcile flow as any other change, including review.
Structured elaboration
How GitOps changes the rollback model. Imperative CI/CD typically has rollback as its OWN distinct mechanism (a "redeploy previous version" pipeline action, sometimes with different permissions or a different code path than a normal deploy). GitOps has NO separate rollback mechanism; a revert is structurally identical to any other change, a Git commit that changes the declared state, reviewed the same way, applied by the same reconciliation loop. This means rollback INHERITS every safety property (review, audit trail, policy-as-code evaluation) normal changes get, rather than needing those properties separately re-implemented for a distinct rollback code path.
Concrete steps to revert a bad deployment.
- Identify the specific commit that introduced the bad change (using the same evidence-first approach any outage investigation follows).
git revert <bad-commit>(or, for a promotion-based flow, a new commit re-pinning the PREVIOUS artifact reference), creating a NEW commit undoing the change, never force-pushing over history.- This revert PR goes through the SAME review as any change (expedited under the emergency-change path if genuinely urgent, but still a real, recorded review, never skipped entirely).
- On merge, the GitOps controller (Argo CD or Flux) detects the Git state has changed and reconciles automatically, no separate "trigger a rollback" action needed beyond the normal merge that any change would need.
Ensuring the cluster reconciles to the reverted state safely. Adapting the same rollback caution used for Terraform to Kubernetes: confirm the revert's computed diff (what the reconciler will actually change) BEFORE merging, the same plan-review discipline applies here to a GitOps revert too, since "just revert the commit" does not guarantee the resulting change is itself risk-free (a revert can, in principle, trigger its own significant change if enough time and other changes have passed since the original commit). Once merged, monitor the reconciliation completing successfully, not just assume merge equals resolved, a revert PR can itself partially fail to apply, exactly like any other change.
Worked example
A bad deployment of checkout-api (a broken config value) via Argo CD:
Imperative CI/CD equivalent (for contrast): trigger the CI/CD pipeline's "redeploy previous version" action, which re-runs the deploy step against the prior artifact; this is a DIFFERENT operation from a normal deploy, often with its own separate permissions and, depending on the pipeline's design, potentially LESS reviewed than a normal deploy would be (rollback is often treated as an emergency action that skips normal process).
GitOps:
git log --oneline apps/checkout-api/overlays/prod/ # identify the bad commit
git revert <bad-commit-sha> # creates a new, reviewable commit
git push # opens/updates the PR
# PR reviewed like any other change (or expedited via the emergency path)
# on merge: Argo CD's application-controller detects the Git change,
# computes the diff, and reconciles automatically
argocd app get checkout-api # confirm sync completed successfully
No separate "rollback" button or pipeline stage exists; the revert PR IS the rollback, reviewed and applied through the identical mechanism every other change uses.
Trade-offs and pitfalls
- Common mistake: treating a GitOps revert as automatically risk-free just because "it's just undoing something." As with a Terraform rollback, a revert's ACTUAL computed effect depends on current state, which may have moved since the original bad commit; skipping the normal plan/diff review specifically because "it's a rollback" is exactly backwards, a rollback deserves the SAME scrutiny as any change, not less.
- Imperative CI/CD's separate rollback mechanism is sometimes FASTER in the moment (a single button/command) but usually LESS reviewed, a real trade-off worth naming explicitly rather than assuming GitOps's model is strictly superior in every dimension; GitOps's rollback is slower by exactly the amount of review it goes through, which is the SAME safety property normal changes get, not an accident.
- A revert PR can itself partially fail to apply, exactly like any other forward change can, treating "the revert PR merged" as equivalent to "the rollback completed" skips confirming the reconciliation itself actually succeeded, a real, easy-to-skip verification step.
- The emergency-change path is available for a GENUINELY urgent rollback, but even that path preserves SOME review (a lightweight, in-the-moment approval) and a mandatory retroactive capture; it is a faster lane through the same fundamental model, not an exception that abandons GitOps's core review-everything property entirely.
You're the on-call lead for a failed deployment across hundreds of instances that needs a rollback. How do you coordinate technical execution, communicate to stakeholders, set verification checkpoints, and decide when to escalate?
Sample Answer
Direct answer
Coordinating a rollback across hundreds of instances as the on-call lead is as much about establishing clear command structure and communication cadence as it is about the technical rollback mechanics: one person makes the call and owns the execution, everyone else has a defined role, and stakeholders get regular updates even when there's nothing new, because silence during an incident causes its own damage.
Structured elaboration
- Establish command: declare yourself (or explicitly designate) incident commander, so decisions aren't made by committee mid-crisis; this doesn't mean you personally run every command, it means you own the decision sequence and who's doing what.
- Assess scope fast: how many instances/regions are affected, is it uniform or partial, is the rollback mechanism automated (a single command that handles all instances) or does it need to be executed per-batch manually?
- Execute in controlled batches, not all at once blindly: even during an emergency, rolling back in verified batches (confirm the first batch actually recovers before proceeding to the rest) catches the case where the rollback ITSELF has a problem, rather than discovering that only after all instances are already mid-rollback.
- Communicate on a fixed cadence: a status update every 5-10 minutes to stakeholders, even a simple "still executing, on track, no new information," because the absence of updates during an active incident causes people to escalate independently or make uncoordinated decisions out of anxiety.
- Set explicit verification checkpoints: after each batch, confirm health (error rate, latency back to baseline) before declaring that batch done and moving to the next; don't assume success just because the deploy command returned.
- Escalation criteria, decided in advance, not improvised: for example, escalate to engineering leadership if the rollback itself is failing or taking meaningfully longer than expected, or escalate to a customer-comms lead if the incident duration crosses a threshold that triggers external communication obligations.
Worked example
A failed deployment across 400 instances: the on-call lead declares incident commander, pulls in two engineers (one executing the batched rollback, one watching dashboards), and a comms lead for stakeholder updates. Rollback executes in four batches of 100 instances, with a two-minute health-verification pause between batches; the third batch reveals a subset of instances failing to roll back cleanly (a stuck deployment), which triggers an explicit escalation to a senior engineer familiar with that specific failure mode rather than the on-call lead attempting to debug it solo under time pressure while the other 300 instances wait.
Trade-offs and pitfalls
Rolling back all instances simultaneously is faster in the best case but riskier: if the rollback mechanism itself has a problem, you discover it only after committing everything, versus a batched approach that catches it early at the cost of some speed. The most common coordination failure isn't technical, it's a lack of a single clear decision-maker, leading to duplicated effort, conflicting actions, or a stalled decision while everyone waits for someone else to call it.
Unlock Full Question Bank
Get access to all Safe Deployment and Rollback Strategies interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.