mirror of
https://github.com/vercel/workflow.git
synced 2026-09-14 19:59:43 +08:00
e00b1a57ee
* perf(world-vercel): batch a fan-out's step-execution queue publishes A `Promise.all` fan-out dispatched one queue message per branch. Those publishes ride the shared default undici agent (8 connections, HTTP/1.1, `pipelining: 1` — see `getQueueDispatcher`), and `handleSuspension` is awaited in full before the first inline step body runs, so an N-branch fan-out paid ~N/8 serialized round trips straight onto time-to-first-step. The `step_created` writes were already batched and HTTP/2-multiplexed; the publishes were the remaining per-branch round trip. Adds an optional `Queue.queueBatch`, implemented on `@vercel/queue`'s `experimental_sendBatch` (0.5.1), and uses it for the batched fan-out fold's publishes. Each commit chunk now publishes in one request instead of up to 32. `queueBatch` reports per-entry outcomes rather than throwing, because a batch can partially fail. `queueMessages` in core keeps the previous all-or-nothing behavior for this call site: it rejects if any entry failed, so the delivery is redelivered and republishes the set, deduped by the per-step `idempotencyKey` the caller already passed. Worlds without `queueBatch` fall back to concurrent single sends. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(core): reject a short queueBatch result set instead of reading it as success `queueMessages` only inspected `error`, so a World whose `queueBatch` returned fewer results than it was given messages reported success for the whole batch. The omitted entries were never published and nothing raised: `handleSuspension` resolved, the delivery was acked, and those steps were never dispatched, so the run stalls with no error recorded anywhere. Reproduced at 64 branches against a World returning half its results: 32 of 63 steps silently lost. world-vercel guards this internally and `@vercel/queue` length-checks its own response, so it was not reachable through the world added here. It is reachable through the interface `building-a-world` opens to third-party worlds, which is where the check belongs. Documented on the interface and in the guide alongside it. Also notes that the batch grouping degenerates to one request per message under WORKFLOW_SEQUENTIAL_REPLAYS=1 (per-step physical topics are one of the routing dimensions groups split on), and corrects the comment claiming the error's `retryable` flag is consumed downstream: nothing reads it yet. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(world-vercel): carry trace context on each batched queue message `experimental_sendBatch` injects the active trace context into the multipart REQUEST headers, and the per-part headers it builds never see it. VQS stores headers per message and re-emits a stored `traceparent` at delivery as `x-vercel-queue-traceparent`, which is what lets a consumer attach a span link back to its producer, so a batched message arrived with no producer context and its `vqs.process` span got no link. `send()` is unaffected: for a single message the request headers ARE that message's headers. At 64 branches that was 63 of 64 step dispatches losing the transport-level producer link. The run's own step tracing was never affected: that carrier travels in the message payload (`WorkflowInvokePayload.traceCarrier`), which is what the consumer builds its trace context from, not a header. Injects the active context into each entry's headers in `queueBatch` — last, so it wins over caller-supplied `opts.headers` exactly as the SDK's own injection does — and honors VERCEL_QUEUE_TRACE_PROPAGATION so that kill switch still covers both paths. `getTraceContextHeaders()` is factored out of `injectTraceContextIntoHeaders` so the two share one source. Verified on the wire against a stub VQS speaking the real batch endpoint: `traceparent` carrying the producer's traceId/spanId lands on all 64 multipart parts through the real SDK, with the per-message idempotency keys still alongside it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Karthik Kalyanaraman <karthik.kalyanaraman@vercel.com>
91 lines
2.7 KiB
YAML
91 lines
2.7 KiB
YAML
packages:
|
|
- workbench/*
|
|
- "!workbench/nitro"
|
|
- packages/*
|
|
- docs
|
|
- tarballs
|
|
|
|
catalog:
|
|
"@biomejs/biome": ^2.4.4
|
|
"@swc/core": 1.15.3
|
|
"@types/json-schema": ^7.0.15
|
|
"@types/node": 22.19.0
|
|
"@vercel/functions": ^3.8.0
|
|
"@vercel/oidc": 3.2.0
|
|
"@vercel/queue": 0.5.1
|
|
"@vitest/coverage-v8": ^4.1.10
|
|
"@vitest/runner": ^4.1.10
|
|
ai: 6.0.116
|
|
enhanced-resolve: 5.19.0
|
|
esbuild: ^0.28.1
|
|
nitro: ^3.0.260610-beta
|
|
semver: 7.7.4
|
|
typescript: ^6.0.3
|
|
ulid: ~3.0.1
|
|
undici: 7.29.0
|
|
vitest: ^4.1.10
|
|
zod: ~4.5.4
|
|
|
|
overrides:
|
|
# `@vercel/queue` accepts any `@vercel/oidc` in the 3.x line, and 3.3+ pulls in
|
|
# `@vercel/cli-config`, whose `xdg-app-paths` dependency instantiates itself at
|
|
# module scope and throws `The "path" argument must be of type string` once a
|
|
# bundler inlines it. Pin the queue client's copy to the last dependency-free
|
|
# release so a bundled queue client keeps working.
|
|
'@vercel/queue>@vercel/oidc': 3.2.0
|
|
# Single @opentelemetry/api instance workspace-wide: with two resolved
|
|
# copies (1.9.0 + 1.9.1), the copy that registers the tracer provider and
|
|
# the copy a package imports can differ, and the API's global-registration
|
|
# version check then hands the importer a noop tracer — world-vercel's
|
|
# spans were silently dropped this way while core's flowed (#2900).
|
|
'@opentelemetry/api': 1.9.1
|
|
rfc6902: 5.1.2
|
|
devalue: 5.9.2
|
|
'@sveltejs/acorn-typescript': 1.0.10
|
|
# postcss < 8.5.18 is vulnerable to CVE-2026-45623 and GHSA-r28c-9q8g-f849
|
|
# (arbitrary file read / .map disclosure via attacker-controlled
|
|
# sourceMappingURL). Forces transitive pins (e.g. next.js's postcss@8.4.31)
|
|
# onto a patched version.
|
|
'postcss@<8.5.18': 8.5.22
|
|
|
|
savePrefix: ""
|
|
|
|
# Keep the lockfile single-document for tools such as Turborepo. CI installs
|
|
# the exact packageManager pin through pnpm/setup.
|
|
pmOnFail: ignore
|
|
|
|
# pnpm 11 requires Node.js 22 or newer. This replaces the two project-local
|
|
# engine-strict .npmrc files, which pnpm 11 no longer reads from repositories.
|
|
engineStrict: true
|
|
|
|
minimumReleaseAge: 2880
|
|
|
|
minimumReleaseAgeExclude:
|
|
- '@turbo/*'
|
|
- 'turbo'
|
|
- '@vercel/*'
|
|
- '@workflow/*'
|
|
- 'esbuild'
|
|
- '@esbuild/*'
|
|
- '@sveltejs/load-config'
|
|
- 'quickjs-wasi'
|
|
- 'devalue'
|
|
# The CI canary lanes pin `next` to a fresh canary at install time
|
|
# (see "Setup canary" in .github/workflows/tests.yml); canaries are
|
|
# usually younger than the 48h gate, and next and its @next/* companion
|
|
# packages (published in lockstep) are Vercel-published.
|
|
- 'next'
|
|
- '@next/*'
|
|
allowBuilds:
|
|
'@parcel/watcher': false
|
|
'@swc/core': false
|
|
'@tailwindcss/oxide': false
|
|
better-sqlite3: false
|
|
bun: false
|
|
cbor-extract: false
|
|
cpu-features: false
|
|
esbuild: true
|
|
protobufjs: false
|
|
sharp: false
|
|
ssh2: false
|