Skip to content
Latchkey

Load test "connection refused" early: target not ready in CI

The single most common CI-only load-test failure is starting the test before the target service is up. k6, Gatling, Locust, and JMeter all report connection refused when nothing is listening yet. The fix is a readiness gate, not a change to the test.

What this error means

The load run shows 100% connection refused or KO from the first request, yet the same test passes locally where the target is already running.

Load test
# k6
dial tcp 127.0.0.1:8080: connect: connection refused
# JMeter
Non HTTP response code: java.net.ConnectException: Connection refused

Common causes

No readiness wait before the test

The pipeline launches the load tool immediately after starting the app, before it finishes binding its port.

A slow-starting dependency behind the target

The app itself waits on a database or cache; until those are ready it does not accept connections, so early requests are refused.

How to fix it

Poll the health endpoint before the load step

  1. Add a bounded wait loop that curls the health endpoint.
  2. Break out once it answers, or fail after a timeout.
  3. Run the load tool only after readiness is confirmed.
Terminal
for i in $(seq 1 30); do
  curl -sf http://localhost:8080/health && break
  sleep 2
done

Use a service healthcheck as the gate

Let the CI service container expose a healthcheck so the job waits for healthy before the load step runs.

.github/workflows/ci.yml
services:
  app:
    image: my/app
    options: >-
      --health-cmd "curl -sf http://localhost:8080/health"
      --health-interval 5s --health-retries 10

How to prevent it

  • Gate every load-test step behind a target readiness check.
  • Wait on the app health endpoint, not a fixed sleep.
  • Expose healthchecks on service containers so CI waits for healthy.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →