Skip to content

Speed up the test-ae HTTP-server sweep (batching / parallelism strategies) #1920

Description

@paul-hammant

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

  1. 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.
  2. 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.

  3. 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.

  4. 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.

  5. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions