-
-
Notifications
You must be signed in to change notification settings - Fork 821
feat(vercel): support queues in local dev #4264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import type { Nitro } from "nitro/types"; | ||
| import { presetsDir } from "nitro/meta"; | ||
| import { resolveModulePath } from "exsolve"; | ||
|
|
||
| /** | ||
| * Configure local development emulation for the Vercel preset. | ||
| * | ||
| * When `vercel.queues.triggers` is configured, propagates the trigger list | ||
| * to runtime config and injects a runtime plugin that binds each topic to | ||
| * the `vercel:queue` hook through env-runner's queue dev bridge. | ||
| * | ||
| */ | ||
| export async function vercelDevModule(nitro: Nitro) { | ||
| if (!nitro.options.dev) { | ||
| return; | ||
| } | ||
|
|
||
| const triggers = nitro.options.vercel?.queues?.triggers; | ||
| if (!triggers?.length) { | ||
| return; | ||
| } | ||
|
|
||
| if (nitro.options.devServer.runner !== "vercel") { | ||
| throw new Error( | ||
| `[vercel:queue] Local queue delivery requires the \`vercel\` dev runner, but \`devServer.runner\` is set to "${nitro.options.devServer.runner}". Remove the \`devServer.runner\` override in your \`nitro.config.ts\` or set it explicitly to \`"vercel"\`.` | ||
| ); | ||
| } | ||
|
|
||
| // Propagate triggers to the runtime plugin via runtimeConfig. | ||
| nitro.options.runtimeConfig.vercel = { | ||
| ...nitro.options.runtimeConfig.vercel, | ||
| queues: { | ||
| triggers: triggers.map((t) => ({ ...t })), | ||
| }, | ||
| }; | ||
|
|
||
| nitro.options.plugins = nitro.options.plugins || []; | ||
| nitro.options.plugins.unshift( | ||
| resolveModulePath("./vercel/runtime/queue.dev", { | ||
| from: presetsDir, | ||
| extensions: [".mjs", ".ts"], | ||
| }) | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,57 @@ | ||||||
| import { send } from "@vercel/queue"; | ||||||
| import type { MessageMetadata } from "@vercel/queue"; | ||||||
| import type { NitroAppPlugin } from "nitro/types"; | ||||||
| import { useRuntimeConfig } from "nitro/runtime-config"; | ||||||
| import { registerVercelQueueConsumer } from "env-runner/runners/vercel/queue-dev"; | ||||||
|
|
||||||
| interface DevTrigger { | ||||||
| topic: string; | ||||||
| retryAfterSeconds?: number; | ||||||
| initialDelaySeconds?: number; | ||||||
| } | ||||||
|
|
||||||
| const queueDevPlugin: NitroAppPlugin = (nitroApp) => { | ||||||
| const triggers = | ||||||
| (useRuntimeConfig() as { vercel?: { queues?: { triggers?: DevTrigger[] } } }).vercel?.queues | ||||||
| ?.triggers || []; | ||||||
|
|
||||||
| if (triggers.length === 0) { | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| const unregisters: Array<() => void> = []; | ||||||
|
|
||||||
| for (const trigger of triggers) { | ||||||
| const unregister = registerVercelQueueConsumer({ | ||||||
| topic: trigger.topic, | ||||||
| retryAfterSeconds: trigger.retryAfterSeconds, | ||||||
| handler: async (message: unknown, metadata: unknown) => { | ||||||
| try { | ||||||
| await nitroApp.hooks.callHook("vercel:queue", { | ||||||
| message, | ||||||
| metadata: metadata as MessageMetadata, | ||||||
| send, | ||||||
| }); | ||||||
| } catch (error) { | ||||||
| console.error("[vercel:queue]", error); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion | π Major | β‘ Quick win Use Nitro/consola logger instead of Switch this to Suggested diff- console.error("[vercel:queue]", error);
+ nitroApp.logger.error("[vercel:queue]", error);As per coding guidelines π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||
| nitroApp.captureError?.(error as Error, { | ||||||
| tags: ["vercel:queue"], | ||||||
| }); | ||||||
| // Rethrow so @vercel/queue schedules a local retry. | ||||||
| throw error; | ||||||
| } | ||||||
| }, | ||||||
| }); | ||||||
| unregisters.push(unregister); | ||||||
| } | ||||||
|
|
||||||
| nitroApp.hooks.hook("close", () => { | ||||||
| for (const unregister of unregisters) { | ||||||
| try { | ||||||
| unregister(); | ||||||
| } catch {} | ||||||
| } | ||||||
| }); | ||||||
| }; | ||||||
|
|
||||||
| export default queueDevPlugin; | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§© Analysis chain
π Script executed:
Repository: nitrojs/nitro
Length of output: 30841
π Script executed:
Repository: nitrojs/nitro
Length of output: 228
π Web query:
env-runner npm package runners/vercel/queue-devπ‘ Result:
The string βenv-runner npm package runners/vercel/queue-devβ doesnβt resolve cleanly to a specific, documented npm package path or file name in the sources I found. What I could confirm: 1) The npm package βenv-runnerβ (unjs/env-runner) exists and provides βrunnersβ including a Vercel runner at the import path env-runner/runners/vercel (not βqueue-devβ). It also documents that it can run across multiple environments/runtimes and exposes a Vercel runner that simulates a Vercel deployment environment with Vercel-like header injection. [1][2] 2) Vercel-specific behavior for env-runner is implemented via βVercelEnvRunnerβ. Its changes include injection of Vercel-related request headers such as x-vercel-deployment-url and x-vercel-id, and it sets process.env values like VERCEL, VERCEL_ENV, VERCEL_REGION, and NOW_REGION in the worker context. [3][4] 3) Vercel Queues are a separate Vercel product (queues durable event streaming). Vercelβs own docs describe authentication and API behavior for Queues, but those docs donβt mention an env-runner βqueue-devβ runner. [5][6] If you meant something else by βqueue-devβ (for example, a specific file/directory name inside env-runner like runners/vercel/queue-dev, or a tag/example used for local queue development), tell me one of the following and I can re-search precisely: - the full npm package name (including scope/version) you intend, or - the exact GitHub file path you saw (repo + path), or - a snippet of the import/require statement youβre using. Citations: - env-runner README shows available runners and explicitly includes VercelEnvRunner at env-runner/runners/vercel and describes Vercel context/header injection. [1] - env-runner repository overview similarly lists Vercel runner and its purpose. [2] - env-runner commit implementing Vercel env var + header injection (VercelEnvRunner). [3] - env-runner commit adding VERCEL_DEPLOYMENT_ID and testing it in VercelEnvRunner. [4] - Vercel Queues docs (product/API) donβt reference env-runner βqueue-devβ. [5][6]
Citations:
π Web query:
registerVercelQueueConsumer env-runner functionπ‘ Result:
There is no documented function named registerVercelQueueConsumer in either the Vercel Queues SDK/docs or the unjs/env-runner project docs. What you likely want (Vercel Queues βpush-modeβ consumer registration): 1) Configure your consumer endpoint trigger in vercel.json using a queue/v2beta experimentalTriggers entry for your route. Vercel invokes that route automatically in push mode. [1][2][3] Example: { "functions": { "app/api/queues/process-order/route.ts": { "experimentalTriggers": [{ "type": "queue/v2beta", "topic": "orders" }] } } } 2) Export your handler using
@vercel/queueβs handleCallback (or handleNodeCallback for certain routers). Messages are acknowledged when your handler completes and retried if the handler throws. [4][3][5] Example: import { handleCallback } from '@vercel/queue'; export const POST = handleCallback(async (message, metadata) => { await processOrder(message); }); How unjs/env-runner fits in: - env-runner is a generic runtime βenvironment runnerβ (it can simulate Vercel via VercelEnvRunner), but its docs donβt mention any Vercel Queue consumer registration helper like registerVercelQueueConsumer. [6][7] - So, in practice, you would still register a Vercel Queues consumer the Vercel way (vercel.json trigger + handleCallback handler), while env-runner may help simulate the Vercel runtime environment during local testing. [6][7][5] If you can share where you saw βregisterVercelQueueConsumerβ (repo/package/link or the relevant file), I can pinpoint whether itβs from a different library or an internal wrapper and map it to the equivalent Vercel Queues APIs.Citations:
π Script executed:
Repository: nitrojs/nitro
Length of output: 2055
Critical: unresolved
env-runner/runners/vercel/queue-devimport pathThis import does not exist in the
env-runnerpackage. The package providesenv-runner/runners/vercelbut not aqueue-devsubpath, andregisterVercelQueueConsumeris not an exported function. Verify the correct import path and function name.Additionally:
console.errorwithconsola.error(required forsrc/presets/**)π§° Tools
πͺ GitHub Check: tests-checks (ubuntu-latest)
[failure] 5-5:
Cannot find module 'env-runner/runners/vercel/queue-dev' or its corresponding type declarations.
π€ Prompt for AI Agents