feat(viewer): instrument SSR with structured Workers Logs telemetry#253
Merged
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
pi-base-topology | 6aa4ce2 | Commit Preview URL Branch Preview URL |
Jun 28 2026, 03:30 PM |
Deploying topology with
|
| Latest commit: |
6aa4ce2
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://af456c6d.topology.pages.dev |
| Branch Preview URL: | https://viewer-ssr-telemetry.topology.pages.dev |
Emit one queryable JSON event per SSR phase to Workers Logs, object-logged
so each field is an indexable key (joinable to the platform's per-invocation
cpuTimeMs/wallTimeMs by requestId):
- request: routeId, status, isolate cold flag, cf.verifiedBotCategory
- bundle_sync: bundle counts + network fetch ms (a valid I/O-bound timer)
- deduce_run: exact spaces/derived counts — the reliable proxy for
deduction CPU, since Date.now() is clamped for CPU-bound
work on Workers and reads ~0
Prefer Cloudflare's verified bot category over a hand-rolled UA regex, and
add an isolate cold-start latch so one-time parse cost can be separated
from steady-state request cost.
Enable observability (logs + traces) on the graphs env too; it was unset,
leaving half the deployment unmonitored.
Telemetry only, no behavior change: this instruments the current eager-SSR
deduction baseline so we can attribute CPU before the lazy-deduction
perf change (perf/viewer-ssr-deduction) lands.
83b790f to
b74d2be
Compare
The completion-time count fired after the eager SSR run finished — which on the eager model happens after the response is sent — so the logs were dropped and deduce_run.spaces read 0 in Workers Logs. Log `planned` (unchecked.length) synchronously at run start instead: captured pre-response, it reliably sizes the deduction work each run intends to do, joinable to platform cpuTimeMs. Restores the deduction loop to its original form (only the start-of-run log is added).
3 tasks
jamesdabbs
added a commit
that referenced
this pull request
Jun 28, 2026
A warm Cloudflare Worker isolate serves many SSR requests but re-downloaded and re-parsed the whole data bundle on every one. Cache the parsed + transformed bundle in isolate (module) scope, keyed by host/branch, and revalidate it against the S3 ETag: an unchanged source now costs a conditional request that 304s and reuses the existing transform instead of re-parsing the entire dataset. The cache is bounded to the few most-recently-used sources (a site serves a single host/branch, so in practice one entry) so a parsed bundle can't accumulate unbounded in a long-lived isolate. SSR only — the client store already persists to localStorage. Instrumentation: add a `cached` flag to the `bundle_sync` Workers Logs event so warm-isolate cache hits (changed:false, cached:true) can be told apart from cold parses (changed:true) when validating against telemetry. Also declare `@cloudflare/workers-types` as a viewer devDependency: app.d.ts (added with the telemetry in #253) references it for `IncomingRequestCfProperties`, but it was only present transitively, so `tsc --noEmit` failed to resolve it.
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.
What & why
Telemetry-only PR — no behavior change. Instruments the current eager-SSR deduction so we can attribute Worker CPU to a phase before changing how deduction runs (lazy-deduction follow-up:
perf/viewer-ssr-deduction, measured against this baseline).serverLog()emits one queryable JSON event per SSR phase to Workers Logs, object-logged so each field is an indexable key — joinable to the platform'scpuTimeMs/wallTimeMsbyrequestId:requestrouteId,status,cold,botCategorybundle_syncmsdeduce_runplanned,resetAlso enables observability (logs + traces) on the graphs env, which was unset.
Validated live on production topology
Deployed and confirmed against real traffic:
request:coldflips correctly;botCategoryseparates verified AI crawlers (~95% of traffic) from non-bots.bundle_sync: every SSR request re-fetches + re-parses the full bundle (~222 spaces / 2102 traits, ~110 ms network) — there is no isolate cache on main.deduce_run: the eager refresh run plans to deduce all 222 spaces per request — confirming the full-DB deduction cost.Why these fields (the non-obvious part)
On Workers
Date.now()is clamped (only advances after I/O), so wall-clock deltas around CPU-bound work read ~0. We lean on platformcpuTimeMsas truth and emit reliable counts as proxies.deduce_runis logged synchronously at run start (planned) because the eager run finishes after the response is sent, so a completion-time count is dropped (it read 0 in the first deploy — caught and fixed). The onemswe keep (bundle_sync) wraps a real network fetch.Custom spans?
Native
tracing.enterSpan(shipped 2026-06-16) is attractive but (a) span durations likely hit the same clamp for CPU phases and (b) the phases worth wrapping live in universal modules whilecloudflare:workersis server-only. Deferred to the perf PR, which creates a server-only SSR seam.traces.enabledstays on for the auto I/O waterfall.Review notes
serverLogno-ops in the browser and during prerender; the deduction loop is unchanged except for one synchronous start-of-run log.svelte-checkclean, unit tests pass, worker build succeeds; deployed to topology (f6fde4c2) and validated end-to-end via the observability API.wrangler versions upload) don't emit to Workers Logs — only deployed versions do — which is why this was validated via a direct topology deploy.