Avoid resolving run data for background steps#2993
Conversation
🦋 Changeset detectedLatest commit: f8f1236 The changes in this PR will be included in the next version bump. This PR includes changesets to release 16 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
🧪 E2E Test Results❌ Some tests failed Summary
❌ Failed Tests▲ Vercel Production (77 failed)astro (7 failed):
example (7 failed):
express (7 failed):
fastify (7 failed):
hono (7 failed):
nextjs-turbopack (7 failed):
nextjs-webpack (7 failed):
nitro (7 failed):
nuxt (7 failed):
sveltekit (7 failed):
vite (7 failed):
💻 Local Development (82 failed)astro-stable (10 failed):
express-stable (8 failed):
fastify-stable (8 failed):
hono-stable (8 failed):
nextjs-turbopack-canary (8 failed):
nextjs-turbopack-stable (8 failed):
nextjs-webpack-stable (8 failed):
nitro-stable (8 failed):
nuxt-stable (8 failed):
vite-stable (8 failed):
📦 Local Production (93 failed)astro-stable (8 failed):
express-stable (9 failed):
fastify-stable (8 failed):
hono-stable (8 failed):
nextjs-turbopack-canary (9 failed):
nextjs-turbopack-stable (9 failed):
nextjs-webpack-canary (9 failed):
nextjs-webpack-stable (9 failed):
nitro-stable (8 failed):
nuxt-stable (8 failed):
vite-stable (8 failed):
🐘 Local Postgres (88 failed)astro-stable (8 failed):
express-stable (8 failed):
fastify-stable (8 failed):
hono-stable (8 failed):
nextjs-turbopack-canary (8 failed):
nextjs-turbopack-stable (8 failed):
nextjs-webpack-canary (8 failed):
nextjs-webpack-stable (8 failed):
nitro-stable (8 failed):
nuxt-stable (8 failed):
vite-stable (8 failed):
🪟 Windows (8 failed)nextjs-turbopack (8 failed):
📋 Other (32 failed)e2e-local-dev-tanstack-start- (8 failed):
e2e-local-postgres-tanstack-start- (8 failed):
e2e-local-prod-tanstack-start- (9 failed):
e2e-vercel-prod-tanstack-start (7 failed):
Details by Category❌ ▲ Vercel Production
❌ 💻 Local Development
❌ 📦 Local Production
❌ 🐘 Local Postgres
❌ 🪟 Windows
❌ 📋 Other
✅ vercel-multi-region
❌ Some E2E test jobs failed:
Check the workflow run for details. |
📊 Workflow Benchmarkscommit Backend:
Avg deltas compare against the most recent benchmark run on Metrics — TTFS: time to first step body (in-deployment start() → first step body, deployment clocks) · STSO: step-to-step overhead (gap between consecutive step bodies) · WO: workflow overhead (whole-run time outside step bodies, in-deployment anchored) · SL: stream latency (in-deployment write → read propagation, readAt - writtenAt) Scenarios — step: one trivial no-op step, no stream; no hooks, so the run stays in turbo mode (in-process fast path) · stream: one streaming step; no hooks, so the run stays in turbo mode (in-process fast path) · hook + stream: registers a hook before one step, which exits turbo mode (dispatch path) · 1020 steps: 1020 trivial sequential steps; STSO is measured between consecutive steps in the given step ranges, and WO is the whole-run overhead outside step bodies · stream latency: parallel reader/writer steps on a dedicated stream; SL is the in-deployment write->read propagation (readAt - writtenAt) 🟢/🔴 mark percentiles within/above target. Targets (p75/p90/p99, ms) — TTFS 200/300/600 · SL 50/60/125 · STSO (1-20) 20/30/60 · STSO (101-120) 30/45/90 · STSO (1001-1020) 40/60/120 All metrics are measured from deployment-side timestamps only. Runs are triggered by an in-deployment route that stamps the anchor ( Cold starts are kept in the numbers on purpose — they are part of real bursty-workload latency. The workbench deployment cold-starts the |
bcf3d68 to
f8f1236
Compare
| workflowRun = { | ||
| ...bgRun, |
There was a problem hiding this comment.
| workflowRun = { | |
| ...bgRun, | |
| // `bgRun` was fetched with `resolveData: 'none'` (an | |
| // optimization for the common early-return case), so its | |
| // `input` is `undefined`. The inline replay below runs | |
| // the workflow function via `runWorkflow`, which hydrates | |
| // the workflow arguments from `workflowRun.input`. | |
| // Re-fetch the run with data resolved so replay receives | |
| // the correct arguments; otherwise a workflow that takes | |
| // input would be replayed with empty arguments, breaking | |
| // deterministic replay. | |
| const fullRun = await world.runs.get(runId, { | |
| resolveData: 'all', | |
| }); | |
| workflowRun = { | |
| ...fullRun, |
Inline-replay-after-background-step reuses a resolveData: 'none' run snapshot whose input is undefined, so workflows that take input are replayed with empty arguments, breaking deterministic replay.
karthikscale3
left a comment
There was a problem hiding this comment.
AI review: One blocking P1 finding.
| ); | ||
| workflowRun = bgRun; | ||
| workflowRun = { | ||
| ...bgRun, |
There was a problem hiding this comment.
AI review: [P1] Re-fetch the resolved run before inline replay
bgRun was loaded with resolveData: 'none', so its input is undefined. When this is the last pending background step, this object becomes workflowRun, and runWorkflow() immediately hydrates arguments from workflowRun.input; that throws Error: Invalid input and fails the workflow. The Linux/Windows unit jobs, Vitest plugin tests, and local-production Hono E2E already reproduce this path. Keep the metadata-only fetch for early-return paths, but fetch with resolveData: 'all' (and re-check terminal status) before falling through to replay.
Summary
Why
Background-step setup only consumes run status, timing, deployment, attributes, and spec version. Resolving input and output data at this point is unnecessary, especially for fan-out workloads and runs with large inputs.
Impact
Reduces data loading and response payload size during background-step startup without changing execution semantics.
Validation
pnpm turbo run build --filter=@workflow/core...pnpm testinpackages/core— 1,483 passed, 3 expected failurespnpm typecheck