Skip to content
Latchkey

How to Gate a Promotion on a Health Check From CI/CD

A health-check gate blocks promotion until the new version reports healthy, so a broken build never takes traffic.

Between deploy and traffic shift, poll the new version health endpoint. Only promote when it passes consistently; if it fails within a timeout, stop the pipeline and leave the previous version serving. This gate underpins every safe strategy on this page.

How it works

The gate is a bounded retry loop against a health endpoint (and, in Kubernetes, readinessProbe results). It converts "the deploy command returned" into "the new version is actually serving correctly" before any traffic moves. A failed gate is a stop signal, not a warning.

Poll readiness and liveness before promoting

.github/workflows/ci.yml
promote:
  runs-on: ubuntu-latest
  steps:
    - name: Wait for readiness in Kubernetes
      run: kubectl rollout status deployment/app-next --timeout=120s
    - name: Confirm health endpoint passes 5 times in a row
      run: |
        PASS=0
        for i in $(seq 1 30); do
          if curl -fsS https://next.internal/healthz; then PASS=$((PASS+1)); else PASS=0; fi
          [ "$PASS" -ge 5 ] && exit 0
          sleep 5
        done
        echo "health gate failed, not promoting"; exit 1
    - name: Promote traffic
      run: kubectl patch service app -p '{"spec":{"selector":{"track":"next"}}}'

Make the health endpoint meaningful

A useful /healthz checks real dependencies (database reachable, migrations applied, cache connected), not just that the process is up. A shallow health check passes while the app is actually broken, defeating the gate.

Pair with automated rollback

A gate that only stops the pipeline still leaves a half-shifted state on some strategies. Pair the gate with an if: failure() rollback (kubectl rollout undo or a traffic swap back) so a failed gate also restores the known good version.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →