Skip to content
5 changes: 5 additions & 0 deletions .changeset/weak-cats-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@workflow/world-vercel": patch
---

Use undici dispatcher for queue client
12 changes: 6 additions & 6 deletions packages/world-vercel/src/http-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ let _dispatcher: RetryAgent | undefined;
* - Connection pooling (up to 8 connections per origin)
* - Retry: Automatic retry on 429/5xx or network errors with exponential backoff
* - Observes Retry-After header if received and lower than 30s
*
* Note: HTTP/2 is disabled because undici's experimental H2 support hangs
* in certain Vercel runtime environments (sveltekit). HTTP/1.1 pipelining
* is also disabled (pipelining: 1) because it causes head-of-line blocking
* that deadlocks the webhook respondWith mechanism. The primary benefits
* from undici here are retry logic and connection pooling.
*/
export function getDispatcher(): RetryAgent {
if (!_dispatcher) {
_dispatcher = new RetryAgent(
new Agent({
connections: 8,
keepAliveTimeout: 10_000,
// H2 is specifically incompatible with SvelteKit on Vercel prod. Everything else
// runs fine.
// TODO: Investigate/fix the failure on SvelteKit so we can re-enable H2.
allowH2: false,
// HTTP/1.1 pipelining is disabled (pipelining: 1) because it causes
// head-of-line blocking that deadlocks the webhook respondWith mechanism.
pipelining: 1,
}),
{
Expand Down
2 changes: 2 additions & 0 deletions packages/world-vercel/src/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ValidQueueName,
} from '@workflow/world';
import * as z from 'zod';
import { getDispatcher } from './http-client.js';
import { type APIConfig, getHeaders, getHttpUrl } from './utils.js';

const MessageWrapper = z.object({
Expand Down Expand Up @@ -84,6 +85,7 @@ export function createQueue(config?: APIConfig): Queue {

const clientOptions = {
region,
dispatcher: getDispatcher(),
...(usingProxy && {
// final path will be /queues-proxy/api/v3/topic/...
// and the proxy will strip the /queues-proxy prefix before forwarding to VQS
Expand Down
47 changes: 20 additions & 27 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ catalog:
"@types/node": 22.19.0
"@vercel/functions": ^3.4.3
"@vercel/oidc": 3.2.0
"@vercel/queue": 0.1.1
"@vercel/queue": 0.1.4
"@vitest/coverage-v8": ^4.0.18
ai: 5.0.104
esbuild: ^0.27.3
Expand Down
Loading