Problem
make test-ae's HTTP portion spins up a large number of real server
instances and runs them strictly serially, which dominates the sweep's
wall-clock. This is a time concern, not a flakiness one (though the
fixed-port design that forces the serialization is the same root cause behind
the port-squatting flake class).
Measured on a local Linux dev box
- ~93 shell tests start a real server (
ae run server.ae / proxy / origin),
out of 366 test_*.sh total.
- Shell tests run at
SH_NPROC=1 (serial) — see Makefile (sh_nproc=${SH_NPROC:-1}).
- Back-to-back, each server test costs ~3–4s (a warm singleton looks like
~0.5s, but in sequence it's ~4s), so the HTTP portion alone is ~5–6 min.
- Per test the time is server compile-check + startup, a
sleep 0.1 poll loop
plus a fixed sleep 0.3, several curl --max-time 5 spawns, and
teardown — very little of it is actual assertion work.
Strategies, roughly by payoff
-
Parallelize the shell tests — biggest single win, lowest effort.
SH_NPROC=1 is the throttle. The reason it's 1 is the fixed-port collision
problem from the flake memory — parallel servers fight over 18120/19100/etc.
Two ways to unlock it:
- Ephemeral ports: have
server.ae bind port 0, print the actual port in
the READY line, and have the shell test read it. Removes the collision
entirely → safe SH_NPROC=$(nproc). This is the right fix and also kills
the port-squatting flake class. Est: 5 min → ~1 min on an 8-core box.
- Cheaper interim: assign each test a unique port derived from its
name/index so parallel runs don't collide, then bump SH_NPROC. Less
robust than port-0 but a small diff.
-
Kill the sleep padding — easy, universal.
Replace grep READY + sleep 0.3 with a real readiness probe (curl-until-
response loop), which the Windows-flake memory already prescribes. Removes
~0.4s guaranteed per test + tightens the poll. ~93 × 0.4s ≈ 35s off, and
it's strictly more correct.
-
Batch multiple assertions per server instance.
Many tests start a whole server to fire 1–3 curls. Where several sibling
tests exercise the same server build, fold them into one server lifecycle
with multiple curl assertions (already done in keepalive's multi-URL curl).
Fewer compile+startup+teardown cycles. Higher effort, test-by-test.
-
Share one long-lived server across a group.
A session-scoped fixture: start one server per behavior family, run all its
tests against it, tear down once. Biggest structural win but the most
invasive — needs a harness concept the sweep doesn't have today.
-
Avoid recompiling the server per test.
ae run re-checks/links each time even on cache hit. ae build once to a
binary, reuse across tests. Marginal here (~0.3–0.5s) since the module cache
already helps.
Suggested first step
#1 (ephemeral ports) + #2 (real readiness probe) compound: correct readiness
enables safe parallelism, they address the time problem AND retire the
port-squatting flake family in one move, and both are mechanical rather than a
per-test rewrite. Prototype on a handful of tests and measure before rolling
the pattern across all 93.
Problem
make test-ae's HTTP portion spins up a large number of real serverinstances and runs them strictly serially, which dominates the sweep's
wall-clock. This is a time concern, not a flakiness one (though the
fixed-port design that forces the serialization is the same root cause behind
the port-squatting flake class).
Measured on a local Linux dev box
ae run server.ae/ proxy / origin),out of 366
test_*.shtotal.SH_NPROC=1(serial) — seeMakefile(sh_nproc=${SH_NPROC:-1}).~0.5s, but in sequence it's ~4s), so the HTTP portion alone is ~5–6 min.
sleep 0.1poll loopplus a fixed
sleep 0.3, severalcurl --max-time 5spawns, andteardown — very little of it is actual assertion work.
Strategies, roughly by payoff
Parallelize the shell tests — biggest single win, lowest effort.
SH_NPROC=1is the throttle. The reason it's 1 is the fixed-port collisionproblem from the flake memory — parallel servers fight over 18120/19100/etc.
Two ways to unlock it:
server.aebind port 0, print the actual port inthe READY line, and have the shell test read it. Removes the collision
entirely → safe
SH_NPROC=$(nproc). This is the right fix and also killsthe port-squatting flake class. Est: 5 min → ~1 min on an 8-core box.
name/index so parallel runs don't collide, then bump
SH_NPROC. Lessrobust than port-0 but a small diff.
Kill the sleep padding — easy, universal.
Replace
grep READY + sleep 0.3with a real readiness probe (curl-until-response loop), which the Windows-flake memory already prescribes. Removes
~0.4s guaranteed per test + tightens the poll. ~93 × 0.4s ≈ 35s off, and
it's strictly more correct.
Batch multiple assertions per server instance.
Many tests start a whole server to fire 1–3 curls. Where several sibling
tests exercise the same server build, fold them into one server lifecycle
with multiple curl assertions (already done in keepalive's multi-URL curl).
Fewer compile+startup+teardown cycles. Higher effort, test-by-test.
Share one long-lived server across a group.
A session-scoped fixture: start one server per behavior family, run all its
tests against it, tear down once. Biggest structural win but the most
invasive — needs a harness concept the sweep doesn't have today.
Avoid recompiling the server per test.
ae runre-checks/links each time even on cache hit.ae buildonce to abinary, reuse across tests. Marginal here (~0.3–0.5s) since the module cache
already helps.
Suggested first step
#1 (ephemeral ports) + #2 (real readiness probe) compound: correct readiness
enables safe parallelism, they address the time problem AND retire the
port-squatting flake family in one move, and both are mechanical rather than a
per-test rewrite. Prototype on a handful of tests and measure before rolling
the pattern across all 93.