Skip to content

Add queue-based health check#743

Merged
TooTallNate merged 43 commits intomainfrom
health-check-thru-queue
Jan 12, 2026
Merged

Add queue-based health check#743
TooTallNate merged 43 commits intomainfrom
health-check-thru-queue

Conversation

@TooTallNate
Copy link
Copy Markdown
Member

@TooTallNate TooTallNate commented Jan 7, 2026

Added a queue-based health check feature that works with Vercel Deployment Protection.

What changed?

  • Implemented a new healthCheck() function (exported at workflow/runtime) that sends messages through the queue infrastructure to verify workflow and step endpoints are operational
  • Added health check message handling in both workflow and step handlers
  • Created HealthCheckPayloadSchema to validate health check messages
  • Added E2E tests for the new queue-based health check functionality
  • Added test API routes in example projects to demonstrate usage

How to test?

  1. Use the new healthCheck() function to check endpoint health:
import { getWorld, healthCheck } from 'workflow/runtime';

const world = getWorld();
const result = await healthCheck(world, 'workflow', { timeout: 30000 });
console.log(result); // { healthy: true } or { healthy: false, error: '...' }
  1. Test with the example API routes:
POST /api/test-health-check
Content-Type: application/json

{
  "endpoint": "workflow", // or "step"
  "timeout": 30000
}

Why make this change?

  • The existing HTTP-based health check using the ?__health query parameter doesn't work with Vercel Deployment Protection enabled.
  • The World interface does not provide an applications reachable URL anyways
  • Going through the queue tests to ensure that the queue is configured correctly as well
  • This health check also ensures that streams are healthy as well, since streams are used to return the result of the health check

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jan 7, 2026

🦋 Changeset detected

Latest commit: 1cf46a6

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

This PR includes changesets to release 18 packages
Name Type
@workflow/web Patch
@workflow/core Patch
@workflow/world Patch
@workflow/cli Patch
@workflow/builders Patch
@workflow/docs-typecheck Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/web-shared Patch
workflow Patch
@workflow/world-local Patch
@workflow/world-postgres Patch
@workflow/world-testing Patch
@workflow/world-vercel Patch
@workflow/astro Patch
@workflow/sveltekit Patch
@workflow/nuxt Patch
@workflow/ai Patch

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 7, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 374 0 11 385
✅ 💻 Local Development 342 0 8 350
✅ 📦 Local Production 342 0 8 350
✅ 🐘 Local Postgres 342 0 8 350
✅ 🪟 Windows 35 0 0 35
❌ 🌍 Community Worlds 135 17 0 152
Total 1570 17 35 1622

❌ Failed Tests

🌍 Community Worlds (17 failed)

mongodb (1 failed):

  • webhookWorkflow

redis (1 failed):

  • webhookWorkflow

starter (14 failed):

  • addTenWorkflow
  • addTenWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly

turso (1 failed):

  • webhookWorkflow

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 34 0 1
✅ example 34 0 1
✅ express 34 0 1
✅ fastify 34 0 1
✅ hono 34 0 1
✅ nextjs-turbopack 34 0 1
✅ nextjs-webpack 34 0 1
✅ nitro 34 0 1
✅ nuxt 34 0 1
✅ sveltekit 34 0 1
✅ vite 34 0 1
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 34 0 1
✅ express-stable 34 0 1
✅ fastify-stable 34 0 1
✅ hono-stable 34 0 1
✅ nextjs-turbopack-stable 35 0 0
✅ nextjs-webpack-stable 35 0 0
✅ nitro-stable 34 0 1
✅ nuxt-stable 34 0 1
✅ sveltekit-stable 34 0 1
✅ vite-stable 34 0 1
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 34 0 1
✅ express-stable 34 0 1
✅ fastify-stable 34 0 1
✅ hono-stable 34 0 1
✅ nextjs-turbopack-stable 35 0 0
✅ nextjs-webpack-stable 35 0 0
✅ nitro-stable 34 0 1
✅ nuxt-stable 34 0 1
✅ sveltekit-stable 34 0 1
✅ vite-stable 34 0 1
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 34 0 1
✅ express-stable 34 0 1
✅ fastify-stable 34 0 1
✅ hono-stable 34 0 1
✅ nextjs-turbopack-stable 35 0 0
✅ nextjs-webpack-stable 35 0 0
✅ nitro-stable 34 0 1
✅ nuxt-stable 34 0 1
✅ sveltekit-stable 34 0 1
✅ vite-stable 34 0 1
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 35 0 0
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 3 0 0
❌ mongodb 34 1 0
✅ redis-dev 3 0 0
❌ redis 34 1 0
✅ starter-dev 3 0 0
❌ starter 21 14 0
✅ turso-dev 3 0 0
❌ turso 34 1 0

📋 View full workflow run

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 7, 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 🥇 Express 0.031s (-35.6% 🟢) 1.007s (~) 0.976s 10 1.00x
🌐 Starter Next.js (Turbopack) 0.040s (+25.2% 🔺) 1.015s (~) 0.975s 10 1.31x
💻 Local Next.js (Turbopack) 0.042s (+4.0%) 1.014s (~) 0.973s 10 1.35x
🌐 Redis Next.js (Turbopack) 0.042s (+19.9% 🔺) 1.018s (~) 0.975s 10 1.37x
💻 Local Nitro 0.043s (+2.4%) 1.007s (~) 0.964s 10 1.39x
🌐 Turso Next.js (Turbopack) 0.066s (-38.3% 🟢) 1.015s (~) 0.949s 10 2.15x
🌐 MongoDB Next.js (Turbopack) 0.120s (-6.5% 🟢) 1.017s (~) 0.897s 10 3.90x
🐘 Postgres Nitro 0.141s (-45.3% 🟢) 1.013s (-0.7%) 0.872s 10 4.57x
🐘 Postgres Next.js (Turbopack) 0.230s (+88.8% 🔺) 1.030s (+0.9%) 0.800s 10 7.47x
🐘 Postgres Express 0.392s (+5.3% 🔺) 1.012s (~) 0.621s 10 12.72x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 0.553s (-27.9% 🟢) 1.597s (-9.7% 🟢) 1.043s 10 1.00x
▲ Vercel Express 0.710s (-8.4% 🟢) 1.475s (-7.9% 🟢) 0.766s 10 1.28x
▲ Vercel Nitro 0.783s (+1.9%) 1.602s (-7.0% 🟢) 0.819s 10 1.41x

🔍 Observability: Next.js (Turbopack) | Express | Nitro

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 1.075s (-3.4%) 2.007s (~) 0.932s 10 1.00x
🌐 Starter Next.js (Turbopack) 1.091s (+1.8%) 2.010s (~) 0.920s 10 1.01x
💻 Local Next.js (Turbopack) 1.098s (~) 2.011s (~) 0.913s 10 1.02x
🌐 Redis Next.js (Turbopack) 1.107s (+2.0%) 2.013s (~) 0.905s 10 1.03x
💻 Local Nitro 1.113s (~) 2.007s (~) 0.894s 10 1.04x
🌐 Turso Next.js (Turbopack) 1.284s (-2.1%) 2.013s (~) 0.729s 10 1.19x
🌐 MongoDB Next.js (Turbopack) 1.311s (+1.4%) 2.015s (~) 0.704s 10 1.22x
🐘 Postgres Next.js (Turbopack) 1.766s (-7.4% 🟢) 2.016s (~) 0.251s 10 1.64x
🐘 Postgres Express 2.248s (+1.9%) 3.015s (~) 0.767s 10 2.09x
🐘 Postgres Nitro 2.439s (+10.3% 🔺) 3.014s (~) 0.575s 10 2.27x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.688s (-3.2%) 3.629s (-0.9%) 0.941s 10 1.00x
▲ Vercel Next.js (Turbopack) 2.690s (-2.2%) 3.735s (-1.8%) 1.045s 10 1.00x
▲ Vercel Express 2.778s (+2.5%) 3.612s (~) 0.834s 10 1.03x

🔍 Observability: Nitro | Next.js (Turbopack) | Express

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 10.511s (-2.5%) 11.010s (~) 0.499s 5 1.00x
🌐 Starter Next.js (Turbopack) 10.599s (+1.2%) 11.012s (~) 0.412s 5 1.01x
💻 Local Next.js (Turbopack) 10.664s (~) 11.019s (~) 0.355s 5 1.01x
🌐 Redis Next.js (Turbopack) 10.710s (+1.5%) 11.017s (~) 0.307s 5 1.02x
💻 Local Nitro 10.790s (~) 11.015s (~) 0.224s 5 1.03x
🌐 Turso Next.js (Turbopack) 12.174s (~) 13.023s (~) 0.849s 5 1.16x
🌐 MongoDB Next.js (Turbopack) 12.268s (~) 13.028s (~) 0.760s 5 1.17x
🐘 Postgres Next.js (Turbopack) 15.186s (+2.8%) 16.043s (+2.6%) 0.857s 5 1.44x
🐘 Postgres Express 20.277s (~) 21.036s (~) 0.759s 5 1.93x
🐘 Postgres Nitro 20.344s (~) 21.033s (~) 0.689s 5 1.94x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 22.178s (-1.4%) 23.077s (~) 0.900s 5 1.00x
▲ Vercel Express 22.451s (-2.4%) 23.195s (-1.8%) 0.745s 5 1.01x
▲ Vercel Nitro 22.488s (+2.6%) 23.281s (+1.7%) 0.793s 5 1.01x

🔍 Observability: Next.js (Turbopack) | Express | Nitro

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 1.320s (-5.9% 🟢) 2.007s (~) 0.687s 15 1.00x
🌐 Redis Next.js (Turbopack) 1.356s (+2.7%) 2.011s (~) 0.655s 15 1.03x
🌐 Starter Next.js (Turbopack) 1.357s (+4.0%) 2.008s (~) 0.651s 15 1.03x
💻 Local Next.js (Turbopack) 1.388s (+0.7%) 2.012s (~) 0.624s 15 1.05x
💻 Local Nitro 1.401s (-0.6%) 2.006s (~) 0.605s 15 1.06x
🐘 Postgres Next.js (Turbopack) 1.740s (+3.9%) 2.014s (~) 0.275s 15 1.32x
🌐 Turso Next.js (Turbopack) 2.116s (-4.4%) 3.014s (~) 0.899s 10 1.60x
🌐 MongoDB Next.js (Turbopack) 2.133s (~) 3.013s (~) 0.880s 10 1.62x
🐘 Postgres Express 2.515s (+3.3%) 3.011s (~) 0.496s 10 1.90x
🐘 Postgres Nitro 2.535s (+4.2%) 3.014s (~) 0.480s 10 1.92x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.782s (-7.5% 🟢) 3.721s (-4.0%) 0.939s 9 1.00x
▲ Vercel Nitro 2.878s (-3.9%) 3.753s (-0.8%) 0.876s 9 1.03x
▲ Vercel Express 3.095s (+6.6% 🔺) 3.855s (+4.6%) 0.760s 8 1.11x

🔍 Observability: Next.js (Turbopack) | Nitro | Express

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 1.939s (-12.7% 🟢) 2.074s (-34.4% 🟢) 0.134s 15 1.00x
💻 Local Nitro 2.158s (-3.0%) 3.050s (-3.8%) 0.893s 10 1.11x
💻 Local Next.js (Turbopack) 2.226s (+4.9%) 3.037s (+2.5%) 0.811s 10 1.15x
🌐 Starter Next.js (Turbopack) 2.463s (+3.7%) 3.009s (~) 0.546s 10 1.27x
🌐 Redis Next.js (Turbopack) 2.524s (+7.8% 🔺) 3.025s (~) 0.501s 10 1.30x
🐘 Postgres Next.js (Turbopack) 2.801s (+9.1% 🔺) 3.041s (+0.7%) 0.240s 10 1.44x
🐘 Postgres Nitro 2.978s (-2.2%) 3.370s (-10.9% 🟢) 0.393s 9 1.54x
🐘 Postgres Express 3.074s (+8.9% 🔺) 3.457s (+14.4% 🔺) 0.382s 9 1.59x
🌐 MongoDB Next.js (Turbopack) 4.682s (+1.5%) 5.182s (~) 0.500s 6 2.41x
🌐 Turso Next.js (Turbopack) 4.779s (+1.8%) 5.186s (~) 0.408s 6 2.46x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.043s (-4.7%) 3.599s (~) 0.556s 9 1.00x
▲ Vercel Nitro 3.276s (-11.5% 🟢) 3.910s (-9.9% 🟢) 0.634s 8 1.08x
▲ Vercel Next.js (Turbopack) 3.355s (-1.1%) 3.873s (-3.6%) 0.518s 8 1.10x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 1.340s (-5.7% 🟢) 2.006s (~) 0.666s 15 1.00x
🌐 Starter Next.js (Turbopack) 1.343s (+2.1%) 2.008s (~) 0.665s 15 1.00x
🌐 Redis Next.js (Turbopack) 1.381s (+4.7%) 2.010s (~) 0.629s 15 1.03x
💻 Local Next.js (Turbopack) 1.418s (+0.7%) 2.014s (~) 0.596s 15 1.06x
💻 Local Nitro 1.427s (~) 2.006s (~) 0.579s 15 1.07x
🐘 Postgres Next.js (Turbopack) 1.756s (~) 2.015s (~) 0.259s 15 1.31x
🐘 Postgres Nitro 1.889s (+6.6% 🔺) 2.327s (+15.7% 🔺) 0.439s 13 1.41x
🌐 Turso Next.js (Turbopack) 2.133s (-3.9%) 3.013s (~) 0.881s 10 1.59x
🌐 MongoDB Next.js (Turbopack) 2.159s (~) 3.016s (~) 0.857s 10 1.61x
🐘 Postgres Express 2.178s (+11.0% 🔺) 3.015s (+35.0% 🔺) 0.837s 10 1.63x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.727s (-13.2% 🟢) 3.648s (-6.1% 🟢) 0.921s 9 1.00x
▲ Vercel Nitro 2.847s (+2.1%) 3.779s (+1.4%) 0.932s 8 1.04x
▲ Vercel Next.js (Turbopack) 3.347s (+19.0% 🔺) 4.313s (+12.8% 🔺) 0.966s 7 1.23x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 1.975s (-12.6% 🟢) 2.077s (-35.6% 🟢) 0.102s 15 1.00x
💻 Local Nitro 2.195s (~) 3.170s (~) 0.974s 10 1.11x
💻 Local Next.js (Turbopack) 2.274s (+5.7% 🔺) 3.216s (+5.5% 🔺) 0.941s 10 1.15x
🐘 Postgres Next.js (Turbopack) 2.346s (-8.6% 🟢) 3.018s (~) 0.672s 10 1.19x
🌐 Starter Next.js (Turbopack) 2.453s (+3.4%) 3.010s (~) 0.557s 10 1.24x
🌐 Redis Next.js (Turbopack) 2.511s (+6.3% 🔺) 3.010s (~) 0.499s 10 1.27x
🐘 Postgres Nitro 2.596s (-9.0% 🟢) 3.012s (-3.7%) 0.416s 10 1.31x
🐘 Postgres Express 2.822s (+3.3%) 3.023s (~) 0.201s 10 1.43x
🌐 MongoDB Next.js (Turbopack) 4.657s (~) 5.186s (~) 0.529s 6 2.36x
🌐 Turso Next.js (Turbopack) 4.721s (+2.1%) 5.181s (~) 0.461s 6 2.39x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.036s (-3.7%) 3.769s (-3.9%) 0.732s 8 1.00x
▲ Vercel Nitro 3.183s (~) 3.718s (-3.0%) 0.535s 9 1.05x
▲ Vercel Express 3.584s (+5.6% 🔺) 4.182s (+1.4%) 0.598s 8 1.18x

🔍 Observability: Next.js (Turbopack) | Nitro | Express

Stream Benchmarks (includes TTFB metrics)
workflow with stream

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 0.108s (-37.7% 🟢) 0.999s (+0.7%) 0.014s (-9.5% 🟢) 1.021s (~) 0.913s 10 1.00x
🌐 Starter Next.js (Turbopack) 0.135s (+44.4% 🔺) 1.006s (~) 0.000s (-100.0% 🟢) 1.014s (~) 0.879s 10 1.25x
💻 Local Next.js (Turbopack) 0.140s (+1.1%) 1.004s (~) 0.023s (+40.4% 🔺) 1.034s (+0.6%) 0.894s 10 1.29x
🌐 Redis Next.js (Turbopack) 0.147s (+26.7% 🔺) 1.005s (~) 0.000s (NaN%) 1.014s (~) 0.867s 10 1.36x
💻 Local Nitro 0.176s (~) 0.993s (~) 0.014s (-3.4%) 1.021s (~) 0.845s 10 1.63x
🌐 MongoDB Next.js (Turbopack) 0.484s (-7.1% 🟢) 0.969s (+4.7%) 0.000s (+Infinity% 🔺) 1.014s (~) 0.530s 10 4.47x
🌐 Turso Next.js (Turbopack) 0.520s (+4.7%) 0.929s (-2.3%) 0.000s (+Infinity% 🔺) 1.015s (~) 0.495s 10 4.80x
🐘 Postgres Next.js (Turbopack) 1.332s (+53.8% 🔺) 1.712s (+51.9% 🔺) 0.000s (-100.0% 🟢) 2.017s (+52.8% 🔺) 0.685s 10 12.30x
🐘 Postgres Nitro 2.160s (-1.7%) 2.882s (+1.3%) 0.000s (~) 3.014s (~) 0.854s 10 19.94x
🐘 Postgres Express 2.402s (+1.6%) 2.638s (-1.5%) 0.000s (NaN%) 3.013s (~) 0.611s 10 22.18x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.855s (-8.3% 🟢) 3.135s (-7.7% 🟢) 0.382s (-23.7% 🟢) 3.992s (-11.0% 🟢) 1.137s 10 1.00x
▲ Vercel Next.js (Turbopack) 2.874s (-4.8%) 3.408s (~) 0.309s (-48.9% 🟢) 4.162s (-7.8% 🟢) 1.289s 10 1.01x
▲ Vercel Nitro 2.913s (-3.3%) 3.161s (-5.6% 🟢) 0.419s (-11.9% 🟢) 4.051s (-5.6% 🟢) 1.138s 10 1.02x

🔍 Observability: Express | Next.js (Turbopack) | Nitro

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World 🥇 Fastest Framework Wins
💻 Local Express 8/8
🐘 Postgres Next.js (Turbopack) 7/8
▲ Vercel Next.js (Turbopack) 4/8
Fastest World by Framework

Winner determined by most benchmark wins

Framework 🥇 Fastest World Wins
Express 💻 Local 8/8
Next.js (Turbopack) 🌐 Starter 5/8
Nitro 💻 Local 8/8
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
  • 🌐 Starter: Community world (local development)
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Jan 7, 2026

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

Project Deployment Review Updated (UTC)
example-nextjs-workflow-turbopack Ready Ready Preview, Comment Jan 12, 2026 10:42pm
example-nextjs-workflow-webpack Ready Ready Preview, Comment Jan 12, 2026 10:42pm
example-workflow Ready Ready Preview, Comment Jan 12, 2026 10:42pm
workbench-astro-workflow Ready Ready Preview, Comment Jan 12, 2026 10:42pm
workbench-express-workflow Ready Ready Preview, Comment Jan 12, 2026 10:42pm
workbench-fastify-workflow Ready Ready Preview, Comment Jan 12, 2026 10:42pm
workbench-hono-workflow Ready Ready Preview, Comment Jan 12, 2026 10:42pm
workbench-nitro-workflow Ready Ready Preview, Comment Jan 12, 2026 10:42pm
workbench-nuxt-workflow Ready Ready Preview, Comment Jan 12, 2026 10:42pm
workbench-sveltekit-workflow Ready Ready Preview, Comment Jan 12, 2026 10:42pm
workbench-vite-workflow Ready Ready Preview, Comment Jan 12, 2026 10:42pm
workflow-docs Ready Ready Preview, Comment Jan 12, 2026 10:42pm

Copy link
Copy Markdown
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Comment thread packages/world-vercel/src/index.ts Outdated
Comment thread packages/world-local/src/index.ts Outdated
Comment thread packages/world-postgres/src/index.ts Outdated
Comment thread packages/world/src/queue.ts Outdated
Copy link
Copy Markdown
Contributor

@pranaygp pranaygp left a comment

Choose a reason for hiding this comment

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

very exciting! left some comments tho

pranaygp and others added 2 commits January 8, 2026 18:38
* feat(web): add self-hosted mode for world configuration

When WORKFLOW_TARGET_WORLD env var is set, the web UI operates in
self-hosted mode where the world configuration is locked to server-side
environment variables and cannot be changed via query params or UI.

- Add getHardcodedConfig server action to detect self-hosted mode
- Modify getWorldFromEnv to use server env vars in hardcoded mode
- Create WorldConfigContext to provide config state app-wide
- Update settings sidebar to show locked state with disabled inputs
- Update connection status to show PostgreSQL backend info
- Mask sensitive values (postgres URL) in hardcoded mode UI

* fix: address PR review feedback

- Remove unused ConfigMode type export
- Fix postgres substring to undefined (tooltip has details)
- Extract buildEnvMapFromProcessEnv helper to reduce duplication
- Remove unused EnvMap import from layout-client
- Import HardcodedConfig from web-shared/server instead of re-defining

* Fix: PostgreSQL URL parameter missing from configParsers, causing loss of postgres URL configuration on page reload in dynamic mode

* fix(cli): clear WORKFLOW_TARGET_WORLD when spawning web server

The CLI sets WORKFLOW_TARGET_WORLD as an env var, which the spawned
Next.js server inherits. This caused the web UI to enter self-hosted
mode even when launched via CLI.

Now we explicitly clear WORKFLOW_TARGET_WORLD from the server's
environment so it starts in dynamic mode where config comes from
query params as intended.

* refactor(web): use server-side env vars for world config

BREAKING CHANGE: The web UI no longer supports configuring the world
backend via URL query parameters. Configuration is now read exclusively
from server-side environment variables.

Changes:
- Remove query param parsing from @workflow/web config.ts
- Add ServerConfig interface with non-sensitive display info
- Update all components to use useServerConfig() hook
- Settings sidebar is now read-only
- CLI passes env vars to spawned web server instead of query params
- Server actions use process.env directly (envMap param reserved for future use)

This simplifies the architecture and improves security by never sending
sensitive data (connection strings, auth tokens) to the client.

* fix(web): fix settings sidebar overflow and shorten data dir path

- Add truncate/overflow handling to settings sidebar config values
- Add shortenPath() helper to abbreviate long file paths:
  - Replaces home directory with ~
  - Shows .../last-two-segments if still too long
- Add title attributes for full path on hover

* Update changeest

---------

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Pranay Prakash <pranay.gp@gmail.com>
// The stream name includes the correlationId for identification.
// The server skips run validation for health check streams.
const fakeRunId = generateHealthCheckRunId();
await world.writeToStream(streamName, fakeRunId, response);
Copy link
Copy Markdown
Contributor

@vercel vercel Bot Jan 9, 2026

Choose a reason for hiding this comment

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

Missing documentation about streaming infrastructure testing in health check function

Fix on Vercel

// NOTE: Health check messages are intentionally unauthenticated for monitoring purposes.
// They only write a simple status response to a stream and do not expose sensitive data.
// The stream name includes a unique correlationId that must be known by the caller.
const healthCheck = parseHealthCheckPayload(message_);
Copy link
Copy Markdown
Contributor

@vercel vercel Bot Jan 9, 2026

Choose a reason for hiding this comment

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

Add rate limiting to health check messages to prevent DoS attacks via queue flooding

Fix on Vercel

Copy link
Copy Markdown
Member

@VaguelySerious VaguelySerious left a comment

Choose a reason for hiding this comment

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

LGTM assuming the workflow-server side gets merged and the tests against vercel prod on this PR then run correctly

Comment thread packages/core/e2e/e2e.test.ts Outdated
//
// For production use on Vercel with Deployment Protection enabled, use the
// queue-based `world.healthCheck()` method instead, which bypasses protection
// by sending messages through the Queue infrastructure.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If we're not deprecating the http health check, it would be nice to have a comment somewhere as to why, and in which scenario we would want to use which health check

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm not addressing the HTTP health check in this PR. I agree it should probably be removed, but IIRC @adriandlam started using it in dev (for some frameworks at least) for the port detection, so we need to double check on that first.

Comment thread packages/core/e2e/e2e.test.ts Outdated
TooTallNate and others added 19 commits January 12, 2026 13:18
- Add HealthCheckPayloadSchema and HEALTH_CHECK_STREAM_PREFIX to @workflow/world
- Add healthCheck() method to Queue interface
- Update workflow and step handlers to detect and respond to health check messages
- Implement healthCheck() in world-local, world-vercel, and world-postgres

The queue-based health check sends a message through the queue pipeline,
which bypasses Vercel's Deployment Protection. The handler writes a response
to a stream that the caller reads to confirm health.

This complements the existing HTTP-based ?__health approach which still works
for local development and when bypass headers are available.
Instead of adding healthCheck to the World interface (which duplicated
the same implementation across all worlds), this is now a utility function
in @workflow/core that takes the World as a parameter.

Usage:
  import { healthCheck } from '@workflow/core';
  const result = await healthCheck(world, 'workflow');

This is cleaner because:
- Single implementation instead of 3 identical ones
- World implementations remain simple
- No changes needed to the World interface
Health check types (HealthCheckPayloadSchema, HealthCheckResult, etc.)
are now defined in @workflow/core since that's where they're used.

The HealthCheckPayloadSchema is still part of QueuePayloadSchema in
world (so the queue accepts health check messages), but it's not
exported from the public API.
)

* Initial plan

* Address PR review comments: export types, fix race condition, improve error handling

Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>

* Add queue-based health check test and document security considerations

Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>

* Replace 'any' type with proper type guards for health check response

Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>

* Extract health check queue names as constants and improve type guards

Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: TooTallNate <71256+TooTallNate@users.noreply.github.com>
Co-authored-by: Pranay Prakash <pranay.gp@gmail.com>
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.

7 participants