Repository navigation
perf(middleware): cheap clones + unboxed futures for hot layers - #30
Merged
Merged
Conversation
MW1 — RateLimitLayer's KeyExtractor and ProxyTrust (String + Vec fields) moved behind a shared Arc<RateLimitConfig>: cloning the per-request service is now refcount bumps instead of copying the extractor and proxy list on every call. MW2 — concrete generic futures replace Pin<Box<dyn Future>> in the four hottest layers, eliminating one heap allocation + vtable dispatch per request per layer: - TraceFuture: pin-project wrapper around Instrumented<S::Future>; gated-span short-circuit, latency records, and error/warn/info events moved into poll. - RequestIdFuture: concrete future shared by RequestIdService and PropagateRequestIdService; response-header insertion moved to poll. - TimeoutFuture: polls handler and deadline side-by-side (handler wins ties), replacing tokio::time::timeout's own boxed wrapper. - Cors: preflight/no-Origin decisions hoisted to synchronous code before future construction; the cross-origin tail keeps its single box (its async tail depends on response values — full unboxing needs tower's Oneshot-style infrastructure, documented as follow-up). Also: JSON/Form content-type fast paths skip the full Mime parse for exact constants; SSE data/comment normalization skips two allocations when no CR is present. Verified on rustc 1.98.0 with CI flags: clippy --workspace --all-features -- -D warnings clean; fmt clean; cargo test --workspace --all-features 171 passed / 0 failed. Full findings in AUDIT_FINDINGS_MIDDLEWARE.md. Co-Authored-By: Claude <noreply@anthropic.com>
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
First implementation wave from
AUDIT_FINDINGS_MIDDLEWARE.md— the middleware-focused optimization audit that studied tower-http 0.6.11 and actix-web 4.15.0/actix-cors 0.7.1 sources for technique transfer.Changes
MW1 — cheap service clones (HIGH)
RateLimitLayer's
KeyExtractor(contains String) andProxyTrust(Vec) moved behind a sharedArc<RateLimitConfig>. Cloning the per-request service was copying both on every call through every stack containing this layer.MW2 — concrete futures (HIGH)
Four hottest layers replaced
Pin<Box<dyn Future>>with pin-project concrete generic futures wrapping the inner future directly — one fewer heap allocation + vtable dispatch per request per layer:TraceFuture<S>RequestIdFuture<S>TimeoutFuture<S>Bonus quick wins (O26)
Verification (rustc 1.98, CI flags)
Benchmark re-run after merge will quantify; audit predicts most of the wrk-mw gap to actix closes via MW2 (per-layer boxes were the structural difference).