Skip to content

e2e: replace fixed-sleep hook waits with event-driven waitForHook helper#1879

Merged
TooTallNate merged 1 commit into
mainfrom
e2e-wait-for-hook
May 4, 2026
Merged

e2e: replace fixed-sleep hook waits with event-driven waitForHook helper#1879
TooTallNate merged 1 commit into
mainfrom
e2e-wait-for-hook

Conversation

@TooTallNate
Copy link
Copy Markdown
Member

Summary

Replaces 8 fixed setTimeout(5_000) waits in hook-related e2e tests with a waitForHook(token, { runId, timeoutMs, intervalMs }) helper that polls getHookByToken until it resolves or the timeout fires.

Background

Hook-related e2e tests (hookWorkflow, hookCleanupTestWorkflow, hookDisposeTestWorkflow, hookWithSleepWorkflow, distributedAbortController ×3) all sleep a fixed 5 seconds before calling getHookByToken, then assume the hook is registered. That budget is:

  • Too tight on slow runtimes — under load (e.g. parallel CI matrix, cold-start-heavy deployments) the workflow may not have reached its createHook call within 5s, and the test fails with HookNotFoundError.
  • Unnecessarily slow on fast runtimes — most invocations register the hook within ~500ms, leaving 4.5s of sunk time per test.

Fix

Adds a waitForHook helper at the top of packages/core/e2e/e2e.test.ts that polls (default 250ms interval, 30s timeout) and exits early on success. The optional runId filter handles eventually-consistent backends where a stale lookup may still resolve to a previous run's hook for the same token (used by hookCleanupTestWorkflow / hookDisposeTestWorkflow token-reuse cases).

Each affected call site replaces the setTimeout(5_000) → getHookByToken(token) pair with waitForHook(token, { runId: run.runId }). Non-hook fixed sleeps (the sleepingWorkflow cancel tests, payload-processing waits in hookWithSleepWorkflow) are untouched.

Verification

pnpm -F @workflow/core typecheck   # clean
pnpm -F @workflow/core build       # clean
pnpm -F @workflow/core test        # 591 unit tests pass

The e2e file is exercised by the dedicated e2e CI pipeline against deployed worlds. Single-file change, 72 insertions / 49 deletions.

Extracted from PR #1300 (snapshot-runtime). The slowness issue was most visible on Vercel under the snapshot runtime where each round-trip is several seconds longer, but the fix makes the tests faster and more reliable on every runtime.

Copilot AI review requested due to automatic review settings April 30, 2026 08:26
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 30, 2026

🦋 Changeset detected

Latest commit: 72f0617

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
example-nextjs-workflow-turbopack Ready Ready Preview, Comment May 3, 2026 5:31pm
example-nextjs-workflow-webpack Ready Ready Preview, Comment May 3, 2026 5:31pm
example-workflow Ready Ready Preview, Comment May 3, 2026 5:31pm
workbench-astro-workflow Ready Ready Preview, Comment May 3, 2026 5:31pm
workbench-express-workflow Ready Ready Preview, Comment May 3, 2026 5:31pm
workbench-fastify-workflow Ready Ready Preview, Comment May 3, 2026 5:31pm
workbench-hono-workflow Ready Ready Preview, Comment May 3, 2026 5:31pm
workbench-nitro-workflow Ready Ready Preview, Comment May 3, 2026 5:31pm
workbench-nuxt-workflow Ready Ready Preview, Comment May 3, 2026 5:31pm
workbench-sveltekit-workflow Ready Ready Preview, Comment May 3, 2026 5:31pm
workbench-vite-workflow Ready Ready Preview, Comment May 3, 2026 5:31pm
workflow-docs Ready Ready Preview, Comment, Open in v0 May 3, 2026 5:31pm
workflow-swc-playground Ready Ready Preview, Comment May 3, 2026 5:31pm
workflow-web Ready Ready Preview, Comment May 3, 2026 5:31pm

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 30, 2026

🧪 E2E Test Results

All tests passed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 1011 0 67 1078
✅ 💻 Local Development 1090 0 86 1176
✅ 📦 Local Production 1090 0 86 1176
✅ 🐘 Local Postgres 1090 0 86 1176
✅ 🪟 Windows 98 0 0 98
✅ 📋 Other 276 0 18 294
Total 4655 0 343 4998

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 91 0 7
✅ example 91 0 7
✅ express 91 0 7
✅ fastify 91 0 7
✅ hono 91 0 7
✅ nextjs-turbopack 96 0 2
✅ nextjs-webpack 96 0 2
✅ nitro 91 0 7
✅ nuxt 91 0 7
✅ sveltekit 91 0 7
✅ vite 91 0 7
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 92 0 6
✅ express-stable 92 0 6
✅ fastify-stable 92 0 6
✅ hono-stable 92 0 6
✅ nextjs-turbopack-canary 79 0 19
✅ nextjs-turbopack-stable 98 0 0
✅ nextjs-webpack-canary 79 0 19
✅ nextjs-webpack-stable 98 0 0
✅ nitro-stable 92 0 6
✅ nuxt-stable 92 0 6
✅ sveltekit-stable 92 0 6
✅ vite-stable 92 0 6
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 92 0 6
✅ express-stable 92 0 6
✅ fastify-stable 92 0 6
✅ hono-stable 92 0 6
✅ nextjs-turbopack-canary 79 0 19
✅ nextjs-turbopack-stable 98 0 0
✅ nextjs-webpack-canary 79 0 19
✅ nextjs-webpack-stable 98 0 0
✅ nitro-stable 92 0 6
✅ nuxt-stable 92 0 6
✅ sveltekit-stable 92 0 6
✅ vite-stable 92 0 6
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 92 0 6
✅ express-stable 92 0 6
✅ fastify-stable 92 0 6
✅ hono-stable 92 0 6
✅ nextjs-turbopack-canary 79 0 19
✅ nextjs-turbopack-stable 98 0 0
✅ nextjs-webpack-canary 79 0 19
✅ nextjs-webpack-stable 98 0 0
✅ nitro-stable 92 0 6
✅ nuxt-stable 92 0 6
✅ sveltekit-stable 92 0 6
✅ vite-stable 92 0 6
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 98 0 0
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 92 0 6
✅ e2e-local-postgres-nest-stable 92 0 6
✅ e2e-local-prod-nest-stable 92 0 6

📋 View full workflow run

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 30, 2026

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 0.042s (-3.7%) 1.006s (~) 0.964s 10 1.00x
💻 Local Next.js (Turbopack) 0.042s 1.004s 0.962s 10 1.02x
💻 Local Express 0.045s (+1.8%) 1.006s (~) 0.960s 10 1.09x
🐘 Postgres Express 0.052s (-9.7% 🟢) 1.012s (~) 0.959s 10 1.26x
🐘 Postgres Nitro 0.059s (-38.1% 🟢) 1.010s (-3.2%) 0.951s 10 1.42x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 1.095s 2.006s 0.911s 10 1.00x
💻 Local Nitro 1.125s (-0.5%) 2.006s (~) 0.881s 10 1.03x
💻 Local Express 1.127s (~) 2.006s (~) 0.880s 10 1.03x
🐘 Postgres Express 1.136s (-0.9%) 2.013s (~) 0.877s 10 1.04x
🐘 Postgres Nitro 1.143s (~) 2.010s (~) 0.866s 10 1.04x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 10.649s 11.022s 0.373s 3 1.00x
🐘 Postgres Express 10.773s (-1.7%) 11.025s (~) 0.252s 3 1.01x
🐘 Postgres Nitro 10.884s (~) 11.019s (~) 0.135s 3 1.02x
💻 Local Nitro 10.932s (~) 11.022s (~) 0.090s 3 1.03x
💻 Local Express 10.964s (~) 11.023s (~) 0.059s 3 1.03x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 14.160s 15.030s 0.870s 4 1.00x
🐘 Postgres Express 14.223s (-2.5%) 15.027s (~) 0.804s 4 1.00x
🐘 Postgres Nitro 14.594s (~) 15.022s (~) 0.428s 4 1.03x
💻 Local Nitro 14.979s (-0.6%) 15.028s (-6.2% 🟢) 0.049s 4 1.06x
💻 Local Express 15.011s (~) 15.531s (+3.3%) 0.520s 4 1.06x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 13.296s (-5.1% 🟢) 14.026s (-3.9%) 0.730s 7 1.00x
🐘 Postgres Nitro 14.131s (+1.2%) 15.025s (+5.0% 🔺) 0.894s 6 1.06x
💻 Local Next.js (Turbopack) 14.756s 15.027s 0.271s 6 1.11x
💻 Local Nitro 16.643s (-0.8%) 17.031s (~) 0.387s 6 1.25x
💻 Local Express 16.785s (+1.1%) 17.032s (~) 0.247s 6 1.26x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.229s (-2.5%) 2.009s (~) 0.779s 15 1.00x
🐘 Postgres Nitro 1.268s (-0.5%) 2.009s (~) 0.741s 15 1.03x
💻 Local Next.js (Turbopack) 1.444s 2.005s 0.561s 15 1.17x
💻 Local Nitro 1.506s (-7.7% 🟢) 2.005s (-3.3%) 0.500s 15 1.22x
💻 Local Express 1.511s (+1.5%) 2.007s (~) 0.496s 15 1.23x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 2.326s (-1.1%) 3.008s (~) 0.682s 10 1.00x
🐘 Postgres Express 2.373s (+0.5%) 3.010s (~) 0.637s 10 1.02x
💻 Local Next.js (Turbopack) 2.625s 3.007s 0.382s 10 1.13x
💻 Local Nitro 2.906s (-7.6% 🟢) 3.108s (-20.0% 🟢) 0.202s 10 1.25x
💻 Local Express 3.064s (+3.8%) 3.759s (+8.9% 🔺) 0.695s 8 1.32x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.438s (-1.4%) 4.012s (~) 0.573s 8 1.00x
🐘 Postgres Nitro 3.504s (+0.7%) 4.011s (~) 0.507s 8 1.02x
💻 Local Next.js (Turbopack) 6.681s 7.415s 0.734s 5 1.94x
💻 Local Nitro 8.392s (+0.5%) 9.022s (~) 0.630s 4 2.44x
💻 Local Express 8.488s (+1.8%) 9.021s (~) 0.533s 4 2.47x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.241s (-1.3%) 2.009s (~) 0.768s 15 1.00x
🐘 Postgres Nitro 1.263s (~) 2.008s (~) 0.745s 15 1.02x
💻 Local Next.js (Turbopack) 1.520s 2.006s 0.486s 15 1.22x
💻 Local Express 1.562s (-17.5% 🟢) 2.006s (-15.1% 🟢) 0.444s 15 1.26x
💻 Local Nitro 1.563s (-16.2% 🟢) 2.006s (-14.3% 🟢) 0.442s 15 1.26x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 2.334s (~) 3.011s (~) 0.676s 10 1.00x
🐘 Postgres Nitro 2.351s (+0.5%) 3.009s (~) 0.658s 10 1.01x
💻 Local Next.js (Turbopack) 2.842s 3.343s 0.502s 9 1.22x
💻 Local Nitro 2.946s (-3.9%) 3.564s (-8.3% 🟢) 0.619s 9 1.26x
💻 Local Express 3.040s (-2.9%) 3.886s (+3.3%) 0.846s 8 1.30x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 3.450s (-0.9%) 4.010s (~) 0.559s 8 1.00x
🐘 Postgres Express 3.489s (~) 4.011s (~) 0.522s 8 1.01x
💻 Local Next.js (Turbopack) 7.165s 7.515s 0.350s 4 2.08x
💻 Local Express 8.780s (~) 9.024s (-2.7%) 0.243s 4 2.54x
💻 Local Nitro 8.936s (-2.3%) 9.529s (-4.9%) 0.593s 4 2.59x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
workflow with 10 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 0.665s 1.004s 0.339s 60 1.00x
🐘 Postgres Express 0.689s (-17.9% 🟢) 1.007s (-1.6%) 0.318s 60 1.04x
🐘 Postgres Nitro 0.831s (+1.2%) 1.006s (~) 0.175s 60 1.25x
💻 Local Express 1.005s (+2.1%) 1.400s (+30.2% 🔺) 0.396s 43 1.51x
💻 Local Nitro 1.095s (+11.7% 🔺) 1.255s (+14.7% 🔺) 0.160s 48 1.65x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
workflow with 25 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.642s (-16.9% 🟢) 2.009s (-11.0% 🟢) 0.367s 45 1.00x
🐘 Postgres Nitro 1.961s (+1.7%) 2.258s (+7.5% 🔺) 0.297s 40 1.19x
💻 Local Next.js (Turbopack) 2.129s 3.007s 0.878s 30 1.30x
💻 Local Nitro 3.035s (~) 3.729s (-0.8%) 0.695s 25 1.85x
💻 Local Express 3.072s (+1.9%) 3.885s (+8.4% 🔺) 0.813s 24 1.87x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
workflow with 50 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.488s (-12.6% 🟢) 4.011s (-8.2% 🟢) 0.524s 30 1.00x
🐘 Postgres Nitro 4.016s (-2.1%) 4.455s (-3.2%) 0.439s 27 1.15x
💻 Local Next.js (Turbopack) 7.091s 7.640s 0.548s 16 2.03x
💻 Local Nitro 9.200s (-1.1%) 9.865s (-1.5%) 0.665s 13 2.64x
💻 Local Express 9.257s (+0.5%) 10.018s (~) 0.762s 12 2.65x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.255s (-9.6% 🟢) 1.008s (~) 0.752s 60 1.00x
🐘 Postgres Nitro 0.280s (-1.2%) 1.007s (~) 0.727s 60 1.10x
💻 Local Next.js (Turbopack) 0.549s 1.021s 0.472s 60 2.15x
💻 Local Express 0.585s (+4.5%) 1.005s (~) 0.419s 60 2.29x
💻 Local Nitro 0.596s (-1.5%) 1.004s (-1.7%) 0.409s 60 2.33x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.413s (-19.0% 🟢) 1.007s (~) 0.594s 90 1.00x
🐘 Postgres Nitro 0.481s (-3.1%) 1.006s (~) 0.525s 90 1.17x
💻 Local Next.js (Turbopack) 2.407s 3.007s 0.600s 30 5.83x
💻 Local Express 2.535s (+0.9%) 3.009s (~) 0.474s 30 6.14x
💻 Local Nitro 2.557s (+0.7%) 3.010s (~) 0.453s 30 6.20x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.665s (-18.8% 🟢) 1.007s (-1.0%) 0.342s 120 1.00x
🐘 Postgres Nitro 0.791s (~) 1.008s (~) 0.217s 120 1.19x
💻 Local Next.js (Turbopack) 9.263s 9.795s 0.532s 13 13.93x
💻 Local Express 11.077s (-1.0%) 11.756s (-1.5%) 0.679s 11 16.66x
💻 Local Nitro 11.085s (-0.9%) 11.574s (-0.8%) 0.488s 11 16.68x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -
Stream Benchmarks (includes TTFB metrics)
workflow with stream

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 0.139s 1.002s 0.010s 1.015s 0.877s 10 1.00x
🐘 Postgres Express 0.176s (-13.9% 🟢) 1.000s (~) 0.001s (-31.3% 🟢) 1.012s (~) 0.835s 10 1.27x
💻 Local Nitro 0.202s (-5.7% 🟢) 1.004s (~) 0.012s (-5.6% 🟢) 1.018s (~) 0.817s 10 1.45x
💻 Local Express 0.204s (+2.7%) 1.004s (~) 0.013s (+4.1%) 1.019s (~) 0.814s 10 1.47x
🐘 Postgres Nitro 0.218s (+6.1% 🔺) 0.996s (~) 0.001s (-33.3% 🟢) 1.009s (~) 0.792s 10 1.57x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - - -
stream pipeline with 5 transform steps (1MB)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.592s (-6.0% 🟢) 1.007s (~) 0.004s (+4.9%) 1.024s (~) 0.432s 59 1.00x
🐘 Postgres Nitro 0.612s (-1.9%) 1.005s (~) 0.004s (-7.4% 🟢) 1.022s (~) 0.409s 59 1.03x
💻 Local Next.js (Turbopack) 0.662s 1.009s 0.010s 1.114s 0.453s 54 1.12x
💻 Local Nitro 0.753s (-10.2% 🟢) 1.012s (~) 0.010s (+6.4% 🔺) 1.024s (-8.2% 🟢) 0.271s 59 1.27x
💻 Local Express 0.864s (+14.2% 🔺) 1.030s (~) 0.014s (+48.9% 🔺) 1.141s (+9.7% 🔺) 0.277s 53 1.46x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - - -
10 parallel streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.986s (+1.7%) 1.126s (-9.8% 🟢) 0.000s (+35.8% 🔺) 1.141s (-9.3% 🟢) 0.155s 53 1.00x
🐘 Postgres Express 1.042s (+8.4% 🔺) 1.578s (+23.5% 🔺) 0.000s (+81.6% 🔺) 1.589s (+21.7% 🔺) 0.547s 38 1.06x
💻 Local Next.js (Turbopack) 1.174s 2.016s 0.000s 2.019s 0.845s 30 1.19x
💻 Local Express 1.236s (+0.9%) 2.021s (~) 0.000s (+40.0% 🔺) 2.023s (~) 0.787s 30 1.25x
💻 Local Nitro 1.282s (+4.8%) 2.022s (~) 0.000s (+200.0% 🔺) 2.024s (~) 0.742s 30 1.30x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - - -
fan-out fan-in 10 streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.729s (-3.5%) 2.104s (-1.8%) 0.000s (-100.0% 🟢) 2.129s (-2.1%) 0.400s 29 1.00x
🐘 Postgres Express 1.885s (+6.3% 🔺) 2.309s (+6.1% 🔺) 0.000s (NaN%) 2.318s (+5.4% 🔺) 0.434s 26 1.09x
💻 Local Next.js (Turbopack) 3.461s 4.028s 0.001s 4.033s 0.572s 15 2.00x
💻 Local Express 3.539s (+2.1%) 4.099s (+1.6%) 0.000s (-41.7% 🟢) 4.102s (+1.6%) 0.563s 15 2.05x
💻 Local Nitro 3.594s (+6.1% 🔺) 4.102s (+1.7%) 0.001s (+62.5% 🔺) 4.105s (+1.7%) 0.511s 15 2.08x
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - - -

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World 🥇 Fastest Framework Wins
💻 Local Next.js (Turbopack) 20/21
🐘 Postgres Express 17/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework 🥇 Fastest World Wins
Express 🐘 Postgres 19/21
Next.js (Turbopack) 💻 Local 21/21
Nitro 🐘 Postgres 18/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates @workflow/core hook-related e2e tests to avoid fixed sleeps by introducing a shared waitForHook() polling helper, improving reliability on slow backends/runtimes and reducing unnecessary waiting on fast ones.

Changes:

  • Added waitForHook(token, { timeoutMs, intervalMs, runId }) helper that polls getHookByToken() until the hook is available (optionally filtering by runId).
  • Replaced multiple setTimeout(5_000)-based waits with waitForHook() across hook registration/resume e2e tests.
  • Standardized one remaining direct setTimeout usage to sleep(3_000).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/e2e/e2e.test.ts Outdated
Hook-related e2e tests (hookWorkflow, hookCleanupTestWorkflow,
hookDisposeTestWorkflow, hookWithSleepWorkflow, distributedAbortController)
previously slept a fixed 5 seconds before calling getHookByToken to wait
for the hook to be registered. On slower runtimes — notably the snapshot
runtime on Vercel where each workflow round-trip is several seconds longer
than replay — that fixed budget is too tight and the test fails with
HookNotFoundError. On faster runtimes it's unnecessarily slow.

Adds a waitForHook(token, { timeoutMs, intervalMs, runId }) helper that
polls until the hook resolves or the timeout (default 30s) expires, with
an optional runId filter for token-reuse tests where eventually-consistent
backends may briefly still report a stale hook. Each hook-wait site now
uses this helper. Non-hook fixed sleeps (workflow-progress polling for
sleepingWorkflow cancel tests, payload-processing waits in
hookWithSleepWorkflow) are unchanged.
@TooTallNate TooTallNate force-pushed the e2e-wait-for-hook branch from 8c293c9 to 72f0617 Compare May 3, 2026 17:27
@TooTallNate TooTallNate enabled auto-merge (squash) May 3, 2026 17:37
@TooTallNate TooTallNate merged commit 98ca60c into main May 4, 2026
151 of 165 checks passed
@TooTallNate TooTallNate deleted the e2e-wait-for-hook branch May 4, 2026 00:05
pranaygp added a commit that referenced this pull request May 4, 2026
…ignal

* origin/main:
  [workbench] Add TanStack Start workbench and tests (#1875)
  Atomically dedupe duplicate step_created/wait_created events in world-local (#1877)
  Split tarball hosting out of docs into its own project (#1893)
  Replace fixed-sleep hook waits with event-driven waitForHook helper (#1879)
pranaygp added a commit that referenced this pull request May 4, 2026
…lier-errors-followups

* origin-https/main:
  [workbench] Add TanStack Start workbench and tests (#1875)
  Atomically dedupe duplicate step_created/wait_created events in world-local (#1877)
  Split tarball hosting out of docs into its own project (#1893)
  Replace fixed-sleep hook waits with event-driven waitForHook helper (#1879)

# Conflicts:
#	pnpm-lock.yaml
VaguelySerious added a commit that referenced this pull request May 4, 2026
Conflicts resolved:

* `packages/core/e2e/e2e.test.ts` (PR #1879 vs. V2 hookDispose helper)
  Drop the locally-defined `waitForHook(expectedRunId)` shadow in the
  hookDisposeTestWorkflow test in favor of the new top-level
  `waitForHook(token, { runId })` API merged from main. Keep V2's
  event-driven `waitForHookDisposal()` helper, which is stricter than
  main's `await sleep(3_000)` (it polls `getHookByToken` for the
  HookNotFoundError signal rather than waiting a fixed interval).

* `packages/world-local/src/storage/events-storage.ts` (PR #1877 vs.
  V2 per-step async mutex)
  Both branches were closing race conditions in the local world's
  step lifecycle. PR #1877 adds filesystem-level O_CREAT|O_EXCL locks
  for `step_created` and `wait_created`; the V2 branch already wraps
  step lifecycle events in an in-process `withStepLock` mutex. They
  compose: the mutex serializes within a single Node process; the
  filesystem lock additionally protects against cross-process races
  (multiple pnpm workers, redelivered queue messages). Resolution
  takes V2's mutex wrap as the base and patches in main's two
  `writeExclusive` claims at the start of the `step_created` and
  `wait_created` handlers, with comments noting the dual-layer
  guarantee.

`packages/core/e2e/utils.ts` auto-merged: V2's nextjs-webpack +
all-Vercel source-map carve-outs preserved alongside main's
`tanstack-start` addition to `hasWorkflowSourceMaps`.

Verified locally: `@workflow/core` and `@workflow/world-local`
typecheck clean; all 343 world-local unit tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ziyak97 pushed a commit to ziyak97/workflow that referenced this pull request May 4, 2026
…ercel#1879)

Hook-related e2e tests (hookWorkflow, hookCleanupTestWorkflow,
hookDisposeTestWorkflow, hookWithSleepWorkflow, distributedAbortController)
previously slept a fixed 5 seconds before calling getHookByToken to wait
for the hook to be registered. On slower runtimes — notably the snapshot
runtime on Vercel where each workflow round-trip is several seconds longer
than replay — that fixed budget is too tight and the test fails with
HookNotFoundError. On faster runtimes it's unnecessarily slow.

Adds a waitForHook(token, { timeoutMs, intervalMs, runId }) helper that
polls until the hook resolves or the timeout (default 30s) expires, with
an optional runId filter for token-reuse tests where eventually-consistent
backends may briefly still report a stale hook. Each hook-wait site now
uses this helper. Non-hook fixed sleeps (workflow-progress polling for
sleepingWorkflow cancel tests, payload-processing waits in
hookWithSleepWorkflow) are unchanged.
TooTallNate added a commit that referenced this pull request May 5, 2026
Resolve conflicts:
- packages/core/src/serialization/* (workflow.ts, step.ts, client.ts,
  codec-devalue.ts, errors.ts, common.ts): take main's version (post-#1849
  SerializationError + post-#1851 first-class Error subclass reducers).
- packages/core/src/serialization/types.ts: take main's per-Error-subclass
  payload shapes; re-add GZIP/ZSTD format prefixes from snapshot-runtime.
- packages/core/src/serialization.ts: take main's V2 helpers
  (dehydrateStepError, hydrateStepError, dehydrateRunError, hydrateRunError,
  getWorldLazy import).
- packages/core/src/runtime.ts: take main's V2 inline-replay loop +
  step-executor + memoizeEncryptionKey + dehydrateRunError patterns; layer
  back snapshot dispatch (useSnapshotRuntime + runWorkflowWithSnapshots)
  before the V2 main replay loop, after run_started setup.
- packages/core/src/runtime/start.ts: take main's getWorldLazy; keep
  snapshot's getWorkflowRuntimeFromEnv usage.
- packages/world-local/src/storage/index.ts: take main's local-var refactor
  + LocalStorage type; layer back snapshots storage entry.
- packages/world-local/src/storage/events-storage.ts: take main's version
  (already includes #1877 dedup atomicity and #1851 Uint8Array passthrough).
- packages/world-postgres: take main's tightened EntityConflictError gate
  (constraint name match) and waitCreated test assertion. Renumber
  snapshot's 0010_add_snapshots_table.sql to 0012; drop branch's duplicate
  0011_add_events_entity_creation_unique_index.sql in favor of main's 0010
  with dedup CTE.
- packages/core/e2e/e2e.test.ts: take main's #1879 waitForHookDisposal.
- .github/workflows/tests.yml: take main's runLabel/artifactSuffix naming
  scheme; keep snapshot's WORKFLOW_RUNTIME env var; take main's Windows
  job structure.
- scripts/create-test-matrix.mjs: extend the runtime cross-product to
  fold runtime into runLabel and artifactSuffix so artifacts/job names
  remain unique.

Snapshot dispatch is now layered on top of V2: when a workflow message
arrives and the run's runtime mode is 'snapshot', runtime.ts delegates
to runWorkflowWithSnapshots and returns. The V2 inline-replay loop and
inline executeStep path remain in place for replay-mode runs and for
inline step execution from background-step deliveries (snapshot mode
will also re-route step queueing to the unified workflow queue in a
follow-up commit so steps hit V2's executeStep instead of stepEntrypoint).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants