Skip to content

I2488 — The HTTP stack is chosen by measurement: the same routes and several hundred open streams on tiny_http and on axum

Decide which HTTP stack the shared server keeps, from a measurement of the two candidates on the same routes, a streamed route and long-lived subscribers, and record the decision so that the repository has one stack and knows why.

READY wave 2 · p1 · deep-work profile · parallel safe

Part of development-runtime — The runtime has a development surface.

Ready. Every dependency is done, so majordomus plan start I2488 will be accepted.

Objective

Decide which HTTP stack the shared server keeps, from a measurement of the two candidates on the same routes, a streamed route and long-lived subscribers, and record the decision so that the repository has one stack and knows why.

Why

ADR 0142, part 3, and step U6 of the owner's UI-performance pack, which the caching work deferred because a cached capability already answers in under 6 ms at p95. That measurement did not include what a streamed UI adds: a connection held open per page. The server runs each request on a thread of its own, at most 64 at once (http/server.rs MAX_HANDLERS), writes a response whole, and has no compression. The owner asked on 2026-10-12 for a top-notch architecture; the pack says the choice is made on same-route benchmarks and that two stacks are not kept.

Current state

tiny_http 0.12, synchronous, four accept threads, a thread per request, 64 handlers at most, WebSocket upgrades on threads of their own, no compression, Content-Length always.

Desired state

The bench harness runs one system target on both stacks behind the same router and executor: a cached JSON route, a server-rendered screen, a streamed response, and N idle WebSocket subscribers (N in 64, 256, 1024) while the first three are timed; p50, p95, p99, memory and threads, on a release build on an idle host. The numbers and the cost of the move (the adapter over Context::execute, blocking handlers on a bounded pool, the deadline and admission rules of I2156 and the remote-caller guard carried over) are written as a decision record. If the decision is to move, the move is its own issue and removes tiny_http in the same change.

Scope

  • apps/majordomus-cli/src/bench
  • apps/majordomus-cli/src/http
  • apps/majordomus-cli/Cargo.toml
  • .ai/repo/adrs
  • docs/PERFORMANCE.md
  • test/cases
  • .ai/repo/project/issues/I2488.yaml

Dependencies

Acceptance criteria

  • One bench target times the same three routes on both stacks, with and without N idle subscribers, and its results are recorded with the commit, the host and the build profile
  • The decision record states the numbers it was decided from and what the move costs, and proposes one stack
  • No second HTTP stack is left in the default build

Validation

  • bin/majordomus plan validate
  • majordomus bench system.http --profile quick --no-write

Evidence required

  • http_stack_benchmark_results
  • http_stack_decision_record

Evidence

None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.

Timeline

started
—
verified
—
completed
—

Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.

Canonical record: .ai/repo/project/issues/I2488.yaml. Read it back with majordomus plan show I2488.

Searches the titles and descriptions of every page this site publishes.