Skip to content

v1.1.0

Choose a tag to compare

@M-Chris M-Chris released this 10 Jul 04:59
· 32 commits to main since this release

@morojs/engine 1.1.0

Performance release. The engine now outperforms uWebSockets.js in both benchmark profiles — real-world (no pipelining) and pipelined — on a single thread, with no API changes and no behavior changes.

Numbers

Alternating best-of-rounds vs uWebSockets.js through the full MoroJS stack (wrk, 100 connections, Node 24, Apple M2 Ultra):

Profile @morojs/engine uWebSockets.js
Real-world (no pipelining) 94,216 req/s 91,247 req/s
Pipelined ×10 (TechEmpower-style) 495,440 req/s 470,520 req/s

The engine won every round of every profile. Versus 1.0.0, pipelined throughput is 3.4× higher (145k → ~495k) and the real-world path gained ~5%.

What changed

  • Pipelined response corking — synchronous responses to pipelined requests now accumulate in a per-connection cork buffer and hit the socket as one write per batch instead of one queued write + event-loop deferral per response. Handlers still run strictly one-at-a-time on a clean stack (request N+1 is surfaced only after handler N returns); async handlers, upgrades, errors, and Connection: close keep their existing paths. The buffer is bounded by the write high-water mark.
  • Zero-allocation hot path on warm connections
    • Header parsing reuses header slots (and their string capacities) across requests instead of reallocating and destroying them each request.
    • The request snapshot (path, query, method, headers, body) is swapped with the parser rather than copied — the previous request's buffers become the parser's scratch for the next one.
    • Responses build into a reusable per-connection buffer and are written straight from it on the fast path — no per-response allocation, no intermediate copy. Oversized buffers (>64 KB) are released so a single large response can't pin memory.
    • Prebuilt status lines for hot statuses; the Connection: header no longer allocates.
  • Bounded as before — all caps (maxHeaders, body/head sizes, write high-water mark, pending-bytes flood cap) apply unchanged; large bodies and responses do not stay pinned to idle keep-alive connections.

Compatibility

  • No API changes. Drop-in for 1.0.0; MoroJS picks it up via ^1.0.0.
  • Same platform/ABI matrix as 1.0.0 (macOS arm64/x64, Linux glibc x64/arm64, Linux musl x64, Windows x64 × Node 20–26), prebuilt with npm provenance.

Verification

  • 128 socket-level wire tests (HTTP conformance + edge + hardening + regression, WebSocket, limits, TLS + TLS-hardening, permessage-deflate) — all passing.
  • 95-check parser unit suite + WebSocket/deflate unit suites under the C++ harness.
  • 234 MoroJS integration tests against this build.
  • libFuzzer corpus runs on the modified parser; ASan/UBSan legs run in CI.