Skip to content

v2.2.0

Choose a tag to compare

@github-actions github-actions released this 25 Aug 07:50
· 21 commits to main since this release

A new flag, --closed: send each connection's next request the instant its
previous response completes, instead of pacing to a fixed -R schedule. The
classic wrk/ab model, opt-in, and the first way to point zrk at a target
without already knowing a rate worth measuring against.

Why

-R is right when you have a rate to test against — a regression gate, an
SLO. It has no good answer for "what's the most this service can actually
sustain at this concurrency?" Guess low and you've only confirmed the service
beats your guess. Guess high and the backlog from that guess dominates: with
nothing to correct against but a target the server never agreed to, the
coordinated-omission-corrected latency histogram fills with queueing delay
that has nothing to do with the server's own response time.

That failure mode is not hypothetical. Driving a real Node/Express server with
a fixed -R well above its ceiling produced a 98% error rate — almost
entirely --deadline misses from chasing a target the server never had a
chance at — with every latency percentile pinned to the deadline itself.
--closed against the same server found the same ~14.9k req/s ceiling
independently measured elsewhere, with a clean p50 of 71µs.

What you get, and what you give up

Coordinated-omission correction needs an intended send time to correct
against. --closed has none — the next send is "now," always — so the
correction doesn't apply, and zrk says so: the final report reads "latency
(closed-loop round-trip)," not "corrected." What comes back is real, not
adjusted: however fast -c connections and the server, between them, actually
managed.

--format json stays schema-compatible. target_rate mirrors achieved_rate
and rate_ratio is always 1.0000 under --closed (config.closed: true),
so a harness that doesn't know about the flag yet still gets coherent numbers
instead of a comparison against the unrelated -R default.

--closed is rejected alongside a ramp (-R A:B) or --deadline — both
presuppose a schedule to ramp along or fall behind, and closed-loop has
neither.

Also

  • Fixed: stdout/stderr writes used positional mode, so two sequential
    writes to the same redirected file (the usage-error message, then the
    usage block) each started at byte 0 and the second silently clobbered the
    first — invisible against a terminal or pipe, real the moment output went
    to a log file. Found while chasing why --closed's new validation errors
    vanished under 2> file but not 2>&1 | head.

Upgrading

Nothing changes unless you pass --closed. zig build test covers 241
tests — 8 new, exercising the flag end to end: CLI validation, the schedule
itself, a live socket run, and the JSON report.