wrk: HTTP Load Testing in CI
wrk drives HTTP load with a handful of threads (-t), keeping many connections (-c) open for a fixed duration (-d), then prints latency and requests/sec.
wrk is the go-to single-binary benchmarker: a few threads saturate a service and it reports p50/p99 with --latency. In CI you point it at a warmed-up endpoint and gate on the numbers.
What it does
wrk opens -c connections spread across -t threads and hammers a single URL for -d seconds, using an event loop so one thread handles many connections. It prints requests/sec, transfer/sec, and (with --latency) the full latency distribution.
Common usage
# 4 threads, 100 connections, 30 seconds, with latency percentiles
wrk -t4 -c100 -d30s --latency http://localhost:8080/
# custom timeout and a Host header
wrk -t4 -c100 -d30s --timeout 5s -H "Host: api.local" http://localhost:8080/healthOptions
| Flag | What it does |
|---|---|
| -t, --threads N | Number of OS threads to use |
| -c, --connections N | Total HTTP connections kept open |
| -d, --duration T | Test duration, e.g. 30s, 2m |
| --latency | Print the detailed latency percentile distribution |
| --timeout T | Socket/request timeout (default 2s) |
| -H, --header <h> | Add an HTTP header to every request |
| -s, --script <lua> | Run a Lua script to shape requests |
In CI
Wait for the server to answer (a curl --retry or a readiness loop) before wrk, or the run reports inflated errors from connections opened before the port was live. wrk itself always exits 0, so parse the output and fail the step yourself: grep the Requests/sec and 99% lines and compare against a threshold.
Common errors in CI
wrk: command not found means it is not installed; on Debian/Ubuntu runners apt-get install -y wrk, on Alpine apk add wrk. unable to connect to localhost:8080 Connection refused means the target is not listening yet, so add a readiness wait. A wall of Socket errors: connect ... read ... timeout usually means -c far exceeds what the server or the runner ulimit allows; lower connections or raise the file-descriptor limit.