Skip to content
Latchkey

curl Wait-Until-Ready: Health Check Loop

Waiting for a service to boot needs a bounded poll loop, not a fixed sleep.

Spinning up a service in CI and then hitting it immediately races the boot. A poll-until-healthy loop is the reliable pattern.

What it does

A readiness loop repeatedly probes a health endpoint until it returns a success status, then continues, or gives up after a maximum number of attempts so the job fails instead of hanging. curl provides the probe; the loop and timeout live in the shell. Using -f makes a non-200 a failure that the loop can detect.

Common usage

Bash
# poll up to ~60s for a 200, then fail the step
for i in $(seq 1 30); do
  if curl -fsS -o /dev/null --max-time 5 http://localhost:8080/health; then
    echo "service ready"; exit 0
  fi
  echo "waiting ($i)..."; sleep 2
done
echo "service did not become healthy"; exit 1

Flags

PieceWhat it does
-fsSFail on >= 400, quiet progress, show errors
-o /dev/nullDiscard the body; we only care about success
--max-time 5Bound each probe so a hang does not stall the loop
sleep / seqBackoff and a bounded number of attempts
--retry (alt)curl can self-retry, but a loop gives clearer control

In CI

Prefer a loop with an attempt cap over a single long sleep: it is faster on the happy path and fails deterministically when the service never starts. Put --max-time on each probe so one slow attempt does not eat the whole budget. Log the attempt number so a flaky boot is visible.

Common errors in CI

curl: (7) Failed to connect to localhost port 8080: Connection refused on early attempts is normal while the service boots; the loop retries. If it never succeeds, the final exit 1 fails the step, which is the intended behavior.

Related guides

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