Skip to content

Refactor Postgres queue execution#2660

Draft
NathanColosimo wants to merge 11 commits into
mainfrom
nathanc/refactor-out-postgres-http-handler
Draft

Refactor Postgres queue execution#2660
NathanColosimo wants to merge 11 commits into
mainfrom
nathanc/refactor-out-postgres-http-handler

Conversation

@NathanColosimo

@NathanColosimo NathanColosimo commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Summary:

  • Run Postgres Graphile jobs through registered in-process queue handlers without changing the World interface.
  • Initialize workflow and step handlers when generated route modules load; retry transient initialization failures and create Astro/SvelteKit handlers once per module.
  • Keep WORKFLOW_LOCAL_BASE_URL authoritative, retain healthy local HTTP delivery for older runtimes, and durably defer jobs while no executor is available.
  • Preserve existing Graphile task names and payloads so queued and suspended runs survive upgrades.

Validation:

  • Core: 64 files, 1,401 tests.
  • Postgres World: 5 files, 158 tests, including the shared real-Postgres World suite.
  • Affected build graph: 24/24 tasks.
  • Mixed-version processes: old Core + new Postgres World; new Core + old Postgres World.
  • Upgrade process: create and suspend a hook run with the old packages, replace the process, then resume and complete it with the new packages.
  • Biome, Core typecheck, changeset status, and diff checks.

Closes #2658
Refs #2656 #1334 #1417

@changeset-bot

changeset-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5828276

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

This PR includes changesets to release 17 packages
Name Type
workflow Patch
@workflow/core Patch
@workflow/world-testing Patch
@workflow/world-postgres Patch
@workflow/astro Patch
@workflow/sveltekit Patch
@workflow/builders Patch
@workflow/cli Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/vitest Patch
@workflow/web-shared Patch
@workflow/web Patch
@workflow/nest Patch
@workflow/nuxt Patch
@workflow/rollup Patch
@workflow/vite 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

@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

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 Jul 9, 2026 8:58pm
example-nextjs-workflow-webpack Ready Ready Preview, Comment Jul 9, 2026 8:58pm
example-workflow Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workbench-astro-workflow Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workbench-express-workflow Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workbench-fastify-workflow Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workbench-hono-workflow Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workbench-nitro-workflow Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workbench-nuxt-workflow Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workbench-sveltekit-workflow Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workbench-tanstack-start-workflow Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workbench-vite-workflow Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workflow-docs Ready Ready Preview, Comment, Open in v0 Jul 9, 2026 8:58pm
workflow-swc-playground Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workflow-tarballs Ready Ready Preview, Comment Jul 9, 2026 8:58pm
workflow-web Ready Ready Preview, Comment Jul 9, 2026 8:58pm

@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

📊 Workflow Benchmarks

commit 5828276 · Thu, 09 Jul 2026 21:14:31 GMT · run logs

Backend: vercel · app: nextjs-turbopack

Metric Scenario Avg (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS stream 1335 (+33%) 1634 🔴 1747 🔴 2040 🔴 30
TTFS hook + stream 1724 (+38%) 1936 🔴 2000 🔴 2144 🔴 30
STSO 1020 steps (1-20) 272 (+14%) 309 🔴 372 🔴 440 🔴 19
STSO 1020 steps (101-120) 456 (+13%) 471 🔴 505 🔴 1467 🔴 19
STSO 1020 steps (1001-1020) 804 (-22%) 872 🔴 938 🔴 939 🔴 19
WO stream 1335 (+33%) 1634 1747 2040 30
WO hook + stream 1724 (+38%) 1936 2000 2144 30
SL stream 4821 (+0.9%) 5467 🔴 5660 🔴 5765 🔴 30
SL hook + stream 4711 (-5.7%) 5018 🔴 5485 🔴 5733 🔴 30
📜 Previous results (2)

380cd99

Thu, 09 Jul 2026 00:16:52 GMT · run logs

vercel / nextjs-turbopack

Metric Scenario Avg (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS stream 1317 1744 🔴 1842 🔴 2462 🔴 30
TTFS hook + stream 1620 1940 🔴 2012 🔴 2344 🔴 30
STSO 1020 steps (1-20) 270 321 🔴 330 🔴 365 🔴 19
STSO 1020 steps (101-120) 432 450 🔴 584 🔴 665 🔴 19
STSO 1020 steps (1001-1020) 849 889 🔴 971 🔴 1032 🔴 19
WO stream 1317 1744 1842 2462 30
WO hook + stream 1620 1940 2012 2344 30
SL stream 4654 5708 🔴 5773 🔴 6117 🔴 30
SL hook + stream 4781 5496 🔴 5783 🔴 5915 🔴 30

51b4853

Wed, 08 Jul 2026 23:10:29 GMT · run logs

vercel / nextjs-turbopack

Metric Scenario Avg (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS stream 1307 1688 🔴 1730 🔴 2131 🔴 30
TTFS hook + stream 1674 1947 🔴 2042 🔴 2428 🔴 30
STSO 1020 steps (1-20) 284 319 🔴 397 🔴 406 🔴 19
STSO 1020 steps (101-120) 409 434 🔴 522 🔴 523 🔴 19
STSO 1020 steps (1001-1020) 818 859 🔴 884 🔴 1161 🔴 19
WO stream 1307 1688 1730 2131 30
WO hook + stream 1674 1947 2042 2428 30
SL stream 5004 5503 🔴 5621 🔴 9659 🔴 30
SL hook + stream 4636 5003 🔴 5413 🔴 5513 🔴 30

Avg deltas compare against the most recent benchmark run on main at the time of this run.

Metrics — TTFS: time to first step body execution · STSO: step-to-step overhead (gap between consecutive step bodies) · WO: workflow overhead (time outside step bodies, client start → last step body exit) · SL: stream latency (first chunk write → visible to the reader)

Scenarios — stream: one step that streams chunks back to the client; no hooks, so the run stays in turbo mode · hook + stream: registers a hook before the same streaming step, which exits turbo mode · 1020 steps: 1020 trivial sequential steps; STSO is measured between consecutive steps in the given step ranges

🟢/🔴 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

TTFS/WO compare client vs deployment clocks and SL compares the step runner’s clock vs the client’s (NTP-synced in CI). WO ends at the last step body exit, the closest observable proxy for the final step-completion request.

@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 1453 0 230 1683
✅ 💻 Local Development 1617 0 219 1836
✅ 📦 Local Production 1617 0 219 1836
✅ 🐘 Local Postgres 1617 0 219 1836
✅ 🪟 Windows 153 0 0 153
✅ 📋 Other 894 0 177 1071
Total 7351 0 1064 8415

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 126 0 27
✅ example 126 0 27
✅ express 126 0 27
✅ fastify 126 0 27
✅ hono 126 0 27
✅ nextjs-turbopack 150 0 3
✅ nextjs-webpack 150 0 3
✅ nitro 126 0 27
✅ nuxt 126 0 27
✅ sveltekit 145 0 8
✅ vite 126 0 27
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 128 0 25
✅ express-stable 128 0 25
✅ fastify-stable 128 0 25
✅ hono-stable 128 0 25
✅ nextjs-turbopack-canary 134 0 19
✅ nextjs-turbopack-stable 153 0 0
✅ nextjs-webpack-canary 134 0 19
✅ nextjs-webpack-stable 153 0 0
✅ nitro-stable 128 0 25
✅ nuxt-stable 128 0 25
✅ sveltekit-stable 147 0 6
✅ vite-stable 128 0 25
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 128 0 25
✅ express-stable 128 0 25
✅ fastify-stable 128 0 25
✅ hono-stable 128 0 25
✅ nextjs-turbopack-canary 134 0 19
✅ nextjs-turbopack-stable 153 0 0
✅ nextjs-webpack-canary 134 0 19
✅ nextjs-webpack-stable 153 0 0
✅ nitro-stable 128 0 25
✅ nuxt-stable 128 0 25
✅ sveltekit-stable 147 0 6
✅ vite-stable 128 0 25
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 128 0 25
✅ express-stable 128 0 25
✅ fastify-stable 128 0 25
✅ hono-stable 128 0 25
✅ nextjs-turbopack-canary 134 0 19
✅ nextjs-turbopack-stable 153 0 0
✅ nextjs-webpack-canary 134 0 19
✅ nextjs-webpack-stable 153 0 0
✅ nitro-stable 128 0 25
✅ nuxt-stable 128 0 25
✅ sveltekit-stable 147 0 6
✅ vite-stable 128 0 25
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 153 0 0
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 128 0 25
✅ e2e-local-dev-tanstack-start- 128 0 25
✅ e2e-local-postgres-nest-stable 128 0 25
✅ e2e-local-postgres-tanstack-start- 128 0 25
✅ e2e-local-prod-nest-stable 128 0 25
✅ e2e-local-prod-tanstack-start- 128 0 25
✅ e2e-vercel-prod-tanstack-start 126 0 27

📋 View full workflow run

@NathanColosimo NathanColosimo force-pushed the nathanc/refactor-out-postgres-http-handler branch from 1ea871b to 34615b2 Compare June 26, 2026 08:00
@NathanColosimo NathanColosimo force-pushed the nathanc/refactor-out-postgres-http-handler branch from 40dfae0 to a2f17c4 Compare June 29, 2026 22:43
NathanColosimo and others added 4 commits June 29, 2026 16:48
The Graphile runner now starts once (registering both job types) as soon
as a workflow executor exists, and each job resolves its executor at
execution time: the registered in-process handler when present, HTTP
against WORKFLOW_LOCAL_BASE_URL when that route is healthy, and
otherwise a health probe plus a durable short-delay redelivery. This
removes the runner-replacement machinery (RunnerTarget diffing,
replaceRunner, the start mutex) and fixes step-queue messages (e.g.
step health checks) never executing when the workflow handler registers
before the queue starts probing.

Also unify workflowEntrypoint's lazy world loading on
getPostgresRegistrationWorld() (covering injected Postgres worlds, not
just env-configured ones) and make getPostgresRegistrationWorld ignore
worlds whose getDeploymentId throws.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The bootstrap loop now probes just the flow health route (the runner
start condition); step routes are warmed exclusively by resolveExecutor
when a step job actually arrives with no registered handler. One probe
mechanism per need, and no HTTP traffic at all in steady state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Core no longer knows Postgres exists. Worlds whose queue executes
in-process handlers declare it via a new optional
Queue.inProcessQueueHandlers capability in @workflow/world, and
world-postgres sets it. Core reacts to the capability only:
workflowEntrypoint registers its queue handler once such a world is
available (immediately when cached, or when later created/injected —
onceInProcessQueueWorld listeners live on globalThis like the world
caches), the step entrypoint registers on POST health probes for such
worlds, and the env-string matching, getDeploymentId probing, and the
flow-route health hook are deleted. Detection now also works for
custom world module paths (e.g. WORKFLOW_TARGET_WORLD=./dist/index.js)
that the string check never matched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread packages/world-postgres/src/queue.ts
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.

Refactor world-postgres queue execution away from loopback HTTP

1 participant