perf: optimize HTTP routing hot paths - #37
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Review findings
Dynamic sibling lookup: included
The router still checks static routes first, dynamic routes in registration order, and catch-all routes last. The new guards are necessary conditions derived from each existing compiled pattern; regex matching, captures, recursive backtracking, and handler selection remain unchanged. Existing lifecycle tests plus focused prefix/suffix extraction coverage exercise registration, unregistration, hot reload, ambiguity/backtracking, and catch-all behavior.
Node 22.19.0 microbenchmark, three-segment routes shaped as
/bench/:value-N/done; values are µs/lookup:The stressed early-match cost is +19 ns because every candidate now checks two precomputed strings. Realistic small tables and every non-early fan-out case improve materially; no radix structure or lookup cache is introduced.
A keep-alive HTTP benchmark with 50 connections and 5,000 failed requests against 500 sibling routes produced median throughput of 3,570 requests/s before and 12,661 requests/s after (+254.6%, three runs).
Middleware priority sorting: excluded
The eight-listener reproduction matched prefix handlers across four trie depths and mixed all five priorities. Baseline lookup plus execution was 1.774 µs/request. Removing sorting reached 0.382 µs, but changes priority semantics and is only an invalid upper bound.
A stable five-priority bucket gather preserved cross-depth and equal-priority order, method/
anyordering, and lifecycle behavior, but measured 2.036 µs/request (+14.8%) due to bucket allocation/flattening. Registration-time sorting alone cannot preserve global order when prefix, postfix, or monitor handlers match at different trie depths. The candidate was therefore removed; production sorting and all existing prefix/postfix/monitor semantics remain unchanged.Synchronous parameter modifiers: included
The compiled resolver now loops synchronously and only creates a promise after observing a provider or modifier thenable. It reads custom thenables once, invokes them with their original receiver, preserves rejection flow, and resumes at the next unprocessed modifier.
Node 22.19.0 results:
A full HTTP listener/controller benchmark with one sync provider and two sync modifiers improved from 10,911 to 14,570 requests/s (+33.5%, 10,000 requests, 50 keep-alive connections).
Verification
pnpm lint— passed (27 files)pnpm build— passedlisten.testafter hook timed out, whilelisten.testalone passed all 12 tests in 42 mspnpm testcannot launch in this checkout because the locked dependencies do not provide the configuredajsexecutable (sh: ajs: not found)--trace-opt --trace-deoptHTTP run —findHandlers,executeRequest, andprocessRequestall optimized with TurboFan; no deoptimization named any of those functionsBenchmark harnesses were temporary and are not tracked.
Greptile Summary
This PR optimizes HTTP routing and controller parameter resolution while preserving existing matching and execution semantics.
Confidence Score: 5/5
The PR appears safe to merge, with no actionable correctness or security issues identified.
The new routing guards are necessary conditions of the existing regular expressions, and the resolver optimization retains modifier ordering, controller binding, thenable handling, and request error propagation.
Important Files Changed
Reviews (1): Last reviewed commit: "perf(api): preserve synchronous paramete..." | Re-trigger Greptile
Security dependency floor
This PR now requires
@antelopejs/interface-api >=0.0.12 <1.0.0and resolves the root runtime dependency to 0.0.12. Version 0.0.12 contains the bounded request-body handling and HTTP 413 response fix shipped in interface-api PR #15, preventing API consumers from resolving the vulnerable 0.0.11 request-body implementation. The lockfile was regenerated with the repository-declared pnpm 10.6.5; no other dependencies or source files changed in this update.