Repository navigation
feat(core): add shared request timing collector and middleware - #389
ChristianPavilonis wants to merge 2 commits into
Conversation
aram356
left a comment
There was a problem hiding this comment.
PR Review
Summary
Adds a generic per-request timing collector (RequestTimings<N, D>) and opt-in, insert-if-absent attachment middleware to edgezero-core, with a shared runtime scenario in the three WASM adapter contract suites. I found no correctness bugs. I'm requesting changes on two API-shape items that are cheap now but become breaking changes once Trusted Server pins a release tag. Neither touches Trusted Server's call sites at 2791ceb.
Findings
Blocking
- 🔧
TimingErrornot#[non_exhaustive]: inconsistent withEdgeError/KvError/ConfigStoreError, and adding it after the tag is breaking (request_timing.rs:17) - 🔧 Hoist
t0out of the mutex: makeselapsed()infallible and the origin structurally immutable;elapsed()currently fails under cross-thread contention (request_timing.rs:100)
Non-blocking
- 🤔 Generic lifecycle names:
headers_ready_total/request_elapsed/resp_bytesmirror TS internals (request_timing.rs:51) - 🤔 Cloudflare clock semantics: workerd's
performance.now()advances only across I/O, and the contract test runs in Chromium (docs/guide/middleware.md:169) - ♻️ Shared fixture via cross-crate
#[path], never run natively: Cloudflare/Fastly/Spintests/contract.rs - ⛏
RequestTimingslacksDebug;must_usemessage wording;with_excluded_pathsreplace semantics undocumented - ⛏ Guide: show paired type aliases (a generic mismatch silently yields no handle); drop the reference to an internal test file
- ⛏ Spec/plan status lines, unchecked tasks, local paths and "keep the PR draft" text are stale relative to the PR
- 🌱 Contention drop counter for native runtimes; config-driven exclusions; exposing the middleware-created handle to outer layers
Behavioral claims above were checked with throwaway probe tests against 9c03cc59: generic-mismatch silence, elapsed() failing under cross-thread contention, exclusion-list replacement, and no handle on the response.
📌 Out of Scope
- Deployed-provider smoke testing is still unchecked in the test plan. It matters most for Cloudflare, where the local harness doesn't use workerd's clock.
- The Axum adapter has no
tests/contract.rs, so the shared timing scenario doesn't run there.
CI Status
- fmt: PASS
- clippy (
--all-features -D warnings): PASS - tests (
--workspace --all-targets): PASS (core: 484 unit tests, plus thecompile_faildoctest) - feature check (
fastly cloudflare spin): PASS - Spin
wasm32-wasip2check: PASS - GitHub: all 22 checks green, including Cloudflare/Fastly/Spin WASM tests
aram356
left a comment
There was a problem hiding this comment.
PR Review
Summary
Second pass at 9c03cc59. It covers areas the earlier review didn't reach: registering the middleware from the manifest, how the handle interacts with State<T>, CI coverage of the compile-fail test, how strong the runtime test is, and documentation consistency. I checked each finding against the code or with a throwaway probe. I'm requesting changes so these land together with the two 🔧 items from the earlier review, before the release tag.
Findings
Inline:
- 🤔
edgezero.tomlcan't register the middleware: aconst fnconstructor fixes it (middleware.rs:86) - 🤔
State<RequestTimings<…>>returns a 500 that points atwith_state(docs/guide/middleware.md:226) - 🤔 CI never runs the compile-fail test (request_timing.rs:40)
- 🤔 Overlapping spans on one slot add up past wall-clock time (request_timing.rs:129)
- 🤔 The runtime test can't catch a stopped clock (tests/support/request_timing.rs:37)
- ⛏
span(slot)?in the guide doesn't compile in a handler (docs/guide/middleware.md:233) - ⛏ The
web_timeexample needs aweb-timedependency (docs/guide/middleware.md:27) - ⛏ Assertions that can't fail (middleware.rs:360, plus four more listed there)
- ⛏
TimingSnapshotlacks theD = ()default (request_timing.rs:45) - 🌱
PhaseSpanhas nofinish/cancel(request_timing.rs:260)
Not attached to a diff line:
-
⛏
configuration.mdnow contradicts the corrected middleware guide:docs/guide/configuration.md:49still says "Manifest-driven middleware are applied in order before routes". This PR corrected the same claim inmiddleware.md:61-62. Suggest reusing that sentence: "Routes are matched first. Middleware then run in registration order for a matched route; unmatched 404/405 requests bypass the middleware chain." -
🌱 The middleware fits only two of Trusted Server's four adapters: at
2791ceb, only Cloudflare and Spin register it.- Fastly creates its collector before the app is built, so it can time AppBuild (
main.rs:128-131). - Axum reimplements insert-if-absent plus the
/healthexclusion as a tower service outsideRouterService(timing.rs:78-99). That also covers 404/405 and gives it a final point to render headers.
This is the gap behind the earlier 🌱 about reaching the middleware-created handle after the router returns. An EdgeZero
Servicewrapper aroundRouterServicewould cover unmatched routes and give every adapter one place to finish timing. - Fastly creates its collector before the app is built, so it can time AppBuild (
CI Status
- fmt: PASS
- clippy (
--all-features -D warnings): PASS - tests (
--workspace --all-targets): PASS - doctests (
--workspace --doc): PASS (1 compile-fail test, 13 ignored) - feature check (
fastly cloudflare spin): PASS - Spin
wasm32-wasip2check: PASS - GitHub: 21/21 checks green
prk-Jr
left a comment
There was a problem hiding this comment.
😃 Reviewed all 11 changed files at 9c03cc5, including focused collector/API and middleware/adapter reviews. No actionable defects found.
The implementation preserves existing collectors, keeps phase and payload updates under one mutex, and follows the documented contention, cancellation, and explicit lifecycle contracts.
Local verification passed:
- cargo fmt --all -- --check
- cargo clippy --workspace --all-targets --all-features -- -D warnings
- cargo test --workspace --all-targets
- cargo test -p edgezero-core: 484 unit tests, two integration tests, and the compile-fail doctest passed; 13 existing doctests ignored
- cargo check --workspace --all-targets --features "fastly cloudflare spin"
- cargo check -p edgezero-adapter-spin --target wasm32-wasip2 --features spin
- Fastly WASM contract suite under Viceroy: all seven tests passed
- Docs lint and formatting
Initial sandbox socket-binding and certificate-store failures cleared on rerun outside the sandbox. All 22 GitHub checks were green at the reviewed commit. Cloudflare/Spin runtime suites and Trusted Server joint validation were not rerun as part of this review.
Summary
Changes
edgezero-core/src/request_timing.rs,src/lib.rsRequestTimings<N, D>, consistent snapshots, compound updates, saturating accumulation, drop-time phase spans and explicit lifecycle marksedgezero-core/src/middleware.rsApplications retain phase enums, domain facts, header names/order, serialization and exposure policy. In particular, Trusted Server retains
Server-Timingrendering; no generic renderer is introduced. Callbacks run synchronously under one nonblocking mutex; panics propagate and poison recovery is best-effort, without rollback or payload validation. Attachment does not finalize requests, measure streamed-body completion, or cover unmatched routes.Closes
No standalone EdgeZero issue. Related consumer work: IABTechLab/trusted-server#1121.
Test plan
Publication-stage reruns against this tree:
cargo test -p edgezero-core— 484 unit tests, two integration tests and one compile-fail doctest passed; 13 existing doctests ignoredcargo test --workspace --all-targetscargo clippy --workspace --all-targets --all-features -- -D warningscargo fmt --all -- --checkcargo check --workspace --all-targets --features "fastly cloudflare spin"cargo check -p edgezero-adapter-spin --target wasm32-wasip2 --features spingit diff --checkEarlier implementation-stage validation, recorded in the committed plan (not rerun during publication):
wasm32-wasip1, Spinwasm32-wasip2, Cloudflarewasm32-unknown-unknownexamples/app-demogates2791ceb46908e6af04ccaae0c10b29d35336a9f4Independent final verification
9c03cc59300363ae5339fc970dded08ede563e98.2791ceb46908e6af04ccaae0c10b29d35336a9f4before requesting review.Coordinated delivery / merge gate
Trusted Server temporarily pins all six EdgeZero dependencies to
9c03cc59300363ae5339fc970dded08ede563e98for integration and joint PR verification, with no local path override and one resolved EdgeZero core identity. That temporary commit pin is not the final delivery pin.Trusted Server #1121 needs an actual approved EdgeZero release tag before merging to main. Replace all temporary pins with that release, regenerate and inspect its lockfile, and revalidate. Review readiness does not waive the release requirement. No merge or tag/release has been performed.
Checklist
{id}syntax where applicable; routing unchangededgezero_core, not directly fromhttp