关于 daemons
Vercel Daemons 是用于持续拉取任务的长运行容器进程,适合队列消费者和工作进程。此技能介绍其配置、部署生命周期、扩缩容、关闭方式及限制,供在 Vercel 应用旁运行后台进程的团队参考。
主要功能
- 01运行基于容器的后台进程
- 02按区域配置实例
- 03重启退出或崩溃的实例
- 04将进程输出转发到项目日志
- 05介绍扩缩容和优雅关闭
- 06说明测试阶段限制与不支持的模式
适用场景
- 01运行常驻队列消费者
- 02在 Vercel 应用旁部署工作进程
- 03配置区域守护进程实例
- 04规划安全发布与任务重试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ vercel/ vercel-plugin --skill daemons安装后在 Claude Code 中输入/daemons确认已加载。
详细介绍
Vercel Daemons
你是 Vercel Daemons 方面的专家。Vercel Daemons 是与应用位于同一项目中、从容器镜像运行的长时间运行的后台进程。
Daemons 在所有套餐中均处于公开测试版。推荐使用时,请说明这一点。
它是什么
Daemon 是项目中的一种命名资源,会在你列出的每个区域运行固定数量的同一容器镜像实例。Vercel 会根据 daemon 的 Dockerfile 或 Containerfile 构建镜像;部署成为生产部署时,Vercel 会推出该镜像;实例退出或崩溃时,Vercel 会重启实例,并将 stdout/stderr 转发到项目的 Logs。Daemons 在 Fluid compute 上运行。
Daemons 无法接收入站流量。它们从队列、工作流引擎或外部 API 拉取任务。
何时使用 Daemons
当进程需要持续循环来获取任务时,请使用 daemon。
| 需求 | 使用 | 原因 |
|---|---|---|
| 常驻队列消费者(Vercel Queues 轮询模式、SQS、Kafka、Redis)、Celery/Sidekiq/BullMQ 工作进程、工作流引擎工作进程、可自托管的 CI 运行器 | Daemons | 长时间运行的循环,每个区域的实例数量固定,无需请求触发 |
| HTTP API、webhook、流式传输、WebSockets | Vercel Functions(⤳ skill: vercel-functions) | Daemons 无法接收流量 |
| 即发即弃的后台任务、扇出、由 Vercel 调用处理函数进行缓冲 | Vercel Queues 推送模式(⤳ skill: queues) | 无服务器、自动扩缩、可用于预览环境 |
| 包含休眠、钩子或审批的持久化多步逻辑 | Vercel Workflows(⤳ skill: workflow) | 持久化步骤和重放 |
| 按计划运行代码 | Cron Jobs(⤳ skill: vercel-functions) | 基于时间的触发器 |
| 隔离运行不可信或 AI 生成的代码 | Vercel Sandbox(⤳ skill: vercel-sandbox) | 临时微型虚拟机 |
| 在一个项目中运行多个前端和后端 | Vercel Services(⤳ skill: vercel-services) | Daemons 与 services 并列运行;它们本身不是 services |
如果用户的工作由请求驱动,请优先选择 Functions 或 Queues 推送模式。只有在必须让某个进程持续运行时,才考虑使用 daemon。
快速开始
在工作进程的源代码目录中添加一个 Dockerfile:
# worker/Dockerfile
FROM node:24-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "worker.js"]
在顶层 daemons 键下声明 daemon:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"daemons": {
"worker": {
"root": "worker/",
"entrypoint": "Dockerfile",
"instances": { "iad1": 2 }
}
}
}
相同的配置也适用于 vercel.toml 中的 [daemons.worker] 表。部署到生产环境。Vercel 会构建镜像,将其以 daemon.worker 的名称推送到 Vercel Container Registry,并在 iad1 中启动两个实例。
Daemons 始终在顶层声明,绝不放在 services 内部。它们会与现有应用(Next.js、Services 或其他应用)并行运行,不会改变 Vercel 的构建方式。
配置参考
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
root | string | 是 | 源目录,相对于 vercel.json。必须位于项目内。其下的文件不会作为静态资源发布 |
entrypoint | string | 是 | Dockerfile 或 Containerfile 的路径,相对于 root。其所在目录为构建上下文 |
instances | Record<region, number> | 是 | 每个区域 ID 的实例数,范围为 0–100。Vercel 仅在列出的区域运行 |
command | string[] | 否 | 替换镜像的 ENTRYPOINT 和 CMD。不会通过 shell 运行 |
resources | { requests: { memory } } | 否 | 1Gi(1 vCPU)、2Gi(1 vCPU,默认值)、4Gi(2 vCPU)、8Gi(4 vCPU) |
instances与replicas:已发布的vercel.json架构和 Build Output API 使用instances。replicas是已弃用的别名;设置了instances时会忽略它。如果项目已在使用replicas,请保持其正常工作,但在新配置中使用instances。- 名称:只能包含小写字母,并以
_、__或一个或多个-连接(worker、email_sender、celery-beat;不能是Worker、worker1、_worker),最多 64 个字符。重复连字符合并后会映射到同一镜像仓库的两个名称(例如a-b和a--b)会导致构建失败。守护进程和服务可以使用相同名称。 - 不支持的字段:守护进程中的
framework、runtime、buildCommand和bindings等服务字段会导致验证失败。 - 构建:镜像针对 Linux
amd64构建。部署环境变量会作为构建参数传入镜像构建过程。 - Shell 功能:
command使用 exec 形式。要展开变量,请使用["sh", "-c", "exec node worker.js --id $WORKER_ID"]。 - 没有
CMD:如果镜像既没有ENTRYPOINT,也没有CMD,且未设置command,构建就会失败。
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"daemons": {
"celery": {
"root": "backend/",
"entrypoint": "Dockerfile",
"command": ["celery", "-A", "app", "worker", "--loglevel=info"],
"instances": { "iad1": 2, "cdg1": 1 },
"resources": { "requests": { "memory": "4Gi" } }
}
}
}
生命周期与扩缩容
- Beta 期间仅限生产环境。 守护进程仅在生产部署中运行。预览部署不会启动守护进程;请在本地运行镜像来测试更改。
- 发布:部署成为生产部署时(部署、提升、即时回滚或已完成的滚动发布),Vercel 会启动新实例,并向前一部署的实例发送
SIGTERM。短时间内两个版本会同时运行,因此两者必须能够使用同一个队列,并兼容相同的数据库架构。 - 镜像、命令和环境变量属于部署。请通过新的生产部署来更改它们。
- 使用
vercel.json扩缩容:更改instances并部署到生产环境。该映射会替换之前的映射;从映射中移除的区域会停止运行。 - 扩缩容覆盖项:在项目控制面板中,选择 Daemons → 选择守护进程 → Set Scaling Overrides。覆盖项会跨部署保留,并优先于
instances,直到通过 Clear scaling overrides 清除。如果vercel.json中对instances的更改似乎没有生效,请先检查是否设置了覆盖项。目前不支持自动扩缩容,也无法通过 CLI 或 API 扩缩容。 - 停止但不删除:将每个区域的值设为
0、将instances设为{},或在控制面板中设置值为0的覆盖项。 - 删除:从
daemons中移除守护进程并部署到生产环境。 - 已暂停的项目会停止所有守护进程实例;项目恢复后,这些实例会重新启动。
优雅关闭
在发布、缩容、移除和手动重启时,Vercel 会发送 SIGTERM,然后默认等待 10 秒再终止进程。请立即停止接收新任务,并完成正在处理的任务。实例可能随时停止,因此任务必须具备幂等性并可安全重试;只有在处理完队列消息后才确认该消息。
// worker/worker.ts
const shutdown = new AbortController();
process.on('SIGTERM', () => shutdown.abort());
async function main(): Promise<void> {
while (!shutdown.signal.aborted) {
await processNextJob(shutdown.signal); // bounded poll; back off when there is no work
}
process.exit(0);
}
void main();
# worker/worker.py
import signal
from threading import Event
shutdown = Event()
signal.signal(signal.SIGTERM, lambda signum, frame: shutdown.set())
while not shutdown.is_set():
process_next_job(shutdown) # bounded poll, finish the current job before returning
从守护进程消费 Vercel 队列
守护进程是 Vercel 队列轮询模式的长期运行消费者。使用 @vercel/queue 中的 PollingQueueClient 并明确指定区域,因为消息只能从发送到的区域接收:
// worker/worker.ts
import { PollingQueueClient } from '@vercel/queue';
const { receive } = new PollingQueueClient({ region: 'iad1' });
const shutdown = new AbortController();
process.on('SIGTERM', () => shutdown.abort());
while (!shutdown.signal.aborted) {
const result = await receive('orders', 'fulfillment', async (message) => {
await processOrder(message); // acknowledged when this resolves, retried if it throws
}, { limit: 10 });
if (!result.ok && result.reason === 'empty') {
await new Promise((r) => setTimeout(r, 1000));
}
}
在与生产者发送消息相同的区域运行守护进程。默认情况下,主题按部署 ID 分区;依赖跨部署消费前,请先阅读轮询模式的版本控制部分。关于生产者端和推送模式消费者,请加载 ⤳ skill: queues。
环境变量和 OIDC
- 每个实例都会接收部署的环境变量。
- 每个实例都会接收一个 OIDC 令牌,该令牌会写入路径由
VERCEL_OIDC_TOKEN_FILE指定的文件,并定期刷新。请使用@vercel/oidc4.0.0 或更高版本(Node.js),或vercel-oidc0.10.0 或更高版本(Python)读取。只读取VERCEL_OIDC_TOKEN的旧版 SDK 无法找到该令牌。
本地开发
vercel dev 不会运行守护进程;它会打印警告并启动项目的其余部分。请改用 Docker 运行守护进程:
vercel env pull # writes .env.local
docker build -t worker worker/
docker run --env-file .env.local worker
日志和可观测性
守护进程的输出会显示在项目的 Logs 中,来源为 daemon,并附有守护进程名称,因此你可以筛选出单个守护进程。项目仪表板的 Daemons 标签页会显示每个守护进程的实例、状态和日志。
构建输出 API
使用 vercel build 或自定义构建器时,.vercel/output/config.json 会将守护进程列为 "daemons": { "worker": {} }(完整集合;被省略的守护进程会停止),每个守护进程都有 .vercel/output/daemons/<name>/.vc-config.json,其中包含 runtime: "container"、一个已位于 Vercel Container Registry 中的 image、instances,以及可选的 command 和 resources。vercel build 会构建并推送镜像,并为你写入这些文件。
限制
| 限制 | 值 |
|---|---|
| 每个区域的实例数 | 每个守护进程 100 个 |
| 每个实例的内存 | 1、2(默认)、4 或 8 GiB |
| 关闭宽限期 | 默认在收到 SIGTERM 后 10 秒 |
| CPU 架构 | Linux amd64 |
Beta 期间适用默认团队配额:Hobby 仅限使用 1–2 GiB 实例,并受每月 vCPU 小时额度限制(额度用完后实例会停止);Pro 允许使用所有规格,但受并发 vCPU 和内存上限约束;Enterprise 为定制方案。调整部署规格前,请查看 Daemons 限制了解当前数值。
Beta 期间不支持:预览部署、入站 HTTP 或 TCP 流量、自动扩缩、持久化本地存储(请使用 Vercel Blob 或 Marketplace 数据库)、在 vercel dev 中运行、作为服务绑定或重写的目标、没有 Dockerfile/Containerfile 的构建,以及根目录为子文件夹(例如 apps/web)的项目。
常见陷阱
- 期待接收流量:监听端口的守护进程不会收到任何内容。请使用 Functions 或 Services 处理请求,并让守护进程拉取任务。
- 在预览环境中测试:Beta 期间,预览部署不会启动守护进程。请部署到生产环境,或在本地运行镜像。
- 扩缩更改被忽略:在清除仪表板中的扩缩覆盖设置前,它的优先级高于
instances。 - 不安全的重叠运行:发布期间,新旧版本会并行运行。请确保消息格式和架构迁移向后兼容。
- 未处理 SIGTERM:进程会在收到
SIGTERM后 10 秒被终止。请确保作业具有幂等性,并仅在完成后确认。 - 在
command中使用 Shell 语法:$VAR和&&不会展开。请用sh -c包装。 - Monorepo 根目录:根目录为子文件夹的项目目前无法添加守护进程。
- OIDC SDK 过旧:请使用
@vercel/oidc≥ 4.0.0 或vercel-oidc≥ 0.10.0,以读取令牌文件。
参考资料
- 📖 文档:https://vercel.com/docs/daemons
- 📖 配置参考:https://vercel.com/docs/daemons/config-reference
- 📖 管理守护进程:https://vercel.com/docs/daemons/managing-daemons
- 📖 限制和配额:https://vercel.com/docs/daemons/limits
- 📖 Build Output API:https://vercel.com/docs/build-output-api/daemons
- 📖 Queues 轮询模式:https://vercel.com/docs/queues/poll-mode
- 📖 Functions、容器与 Daemons:https://vercel.com/kb/guide/vercel-functions-containers-daemons