convoy docs
Search

Progressive rollout

How convoy detects a failed rollout and rolls back to the last healthy render.

A rollout is the period after convoy applies a new render. During a rollout, convoy waits for the resources of that render to become healthy. If they do not become healthy before the deadline, the rollout fails. With a rollback policy, convoy then applies the last healthy render again.

Rollout state machine Pick a scenario and step through renders and time. The deadline is 2m. A good render becomes healthy 30s after its apply.
FromEventToRender on the cluster
none, or another rendernew render, or /sync?force=trueProgressingnew render
Progressingall resources healthySucceedednew render
Progressingdeadline passed, rollback possibleRolledBacklast healthy render
Progressingdeadline passed, no rollbackFailednew render
Progressingstill convergingProgressingnew render
Failedall resources become healthySucceedednew render
not RolledBacksync wave timed out, OnWaveFailure, rollback possibleRolledBacklast healthy render
not RolledBacksync wave timed out, no rollbackFailedthe waves of the new render that convoy applied

Enable the failure policy#

Set spec.failurePolicy.rollback and spec.healthAssessment.deadline:

yaml
apiVersion: core.convoy.kumodo.io/v1alpha1
kind: Release
metadata:
  name: podinfo
spec:
  # source, content and clusterRef are not shown
  healthAssessment:
    deadline: 5m
    globalRuleSetSelector:
      matchLabels:
        convoy.kumodo.io/rules: default
  failurePolicy:
    rollback: OnReleaseFailure
rollbackWhat convoy does when the rollout fails
NeverSets the rollout to Failed. The new render stays on the cluster.
OnReleaseFailureRolls back when the resources are not healthy before the deadline.
OnWaveFailureRolls back on the conditions of OnReleaseFailure. Also rolls back when a sync wave with waitForHealthyWithTimeout times out.

A rollback value other than Never requires spec.healthAssessment.deadline. Without a deadline, a rollout cannot fail, so the API rejects the Release.

Rollout states#

convoy writes the rollout to status.rollout:

yaml
status:
  rollout:
    state: RolledBack
    renderRef: sha256:…        # the render of this rollout
    startedAt: "2026-11-01T10:00:00Z"
    message: release did not become healthy within 5m0s; rolled back to sha256:…
  lastHealthy:
    renderRef: sha256:…        # the rollback target
StateMeaningRolloutSucceeded condition
Progressingconvoy waits for the resources of the render to become healthy.Unknown
SucceededAll resources of the render became healthy.True
FailedThe deadline passed, or a sync wave timed out, and convoy did not roll back.False
RolledBackThe rollout failed and convoy applied the last healthy render.False

Succeeded and RolledBack stay until a new render starts a new rollout. A Failed rollout changes to Succeeded if all resources become healthy later.

How convoy decides that a rollout failed#

The deadline starts at status.rollout.startedAt. At each reconcile, convoy reads the health state of each resource from the ReleaseInventory:

  • All resources of the render are Healthy: the rollout succeeds.
  • At least one resource of the render is Progressing or Degraded, and the deadline passed: the rollout fails.
  • In all other cases, convoy waits. A resource in Unknown state does not fail a rollout.

convoy uses only health states that the observer assessed for this render. An assessment of an earlier render does not count.

While a rollout is Progressing, convoy checks it again at least every 10 seconds.

Sync-wave failures#

A sync wave with waitForHealthyWithTimeout waits until the previous wave is healthy. When the wait is longer than the timeout, the wave fails. The timeout starts at the first apply of the previous wave. convoy does not apply the waiting wave. The result depends on the failure policy:

spec.failurePolicyRollout stateApplied reason
rollback: OnWaveFailure, and the rollback succeedsRolledBackRolledBack
Any other value, or the rollback failsFailedRolloutFailed
Not setNo rolloutWaveFailed

convoy checks the wave gate at each apply, also after the rollout is Succeeded. A cluster-wave timeout (ClusterWaveFailed) does not change the rollout.

The last healthy render#

status.lastHealthy is the most recent render whose resources were all healthy. At each reconcile, convoy checks the render of that reconcile. When all its resources are Healthy for this render, convoy sets lastHealthy to it. convoy does this for every Release, also without a failure policy. A failure does not clear it, so the previous good render stays available as a rollback target.

Without spec.healthAssessment, each render counts as healthy. convoy then sets lastHealthy to each new render, also when the apply of that render fails.

A rollback needs:

  • a value in status.lastHealthy
  • a render store, because convoy reads the last healthy render from it

How convoy applies a rollback#

convoy reads the last healthy render from the render store and applies it. This apply is smaller than a usual apply:

  • It applies all objects in one step. It does not use the sync-wave order.
  • It does not run the pre-apply dry run.
  • It does not run lifecycle hooks.
  • It does not add a history entry, and it does not run the garbage collection of the render store.
  • With spec.syncPolicy.prune.orphaned, it prunes the objects that the failed render added.
  • It writes the objects of the last healthy render to the ReleaseInventory.

After the rollback, Applied is True with reason RolledBack. status.lastSuccessful contains the last healthy render. While the state is RolledBack, convoy applies the last healthy render again at each reconcile. The observer uses it as the desired state for drift.

If the rollback apply fails, convoy logs the error and keeps the state RolledBack. It does not apply the failed render again. It tries the rollback again at the next reconcile.

Other status changes#

  • A failure before the rollout step, for example a source or cluster failure, keeps the rollout in status.rollout unchanged.
  • When you remove spec.failurePolicy, convoy removes status.rollout. The RolloutSucceeded condition keeps its last value.

Start a rollout again#

To clear a Failed or RolledBack rollout and apply the current render again, send a forced sync:

sh
kubectl convoy release sync podinfo --force

A forced sync starts a new Progressing rollout. It also skips the pre-apply dry run. convoy handles each forced sync one time, also when the reconcile fails before the rollout step. In that case, send the forced sync again.

Manual sync mode#

convoy decides the rollout before it checks for a /sync request. A new render opens a Progressing rollout while the apply waits for /sync. A RolledBack rollout applies the last healthy render without a /sync request.

Pins#

A pin on the Release overrides the rollout. While a pin is set, convoy applies the pinned render and does not run the rollout state machine. Only a sync-wave timeout can change status.rollout. See Pin and history.

In the code

convoy v0.9.0