任务
Nitro tasks 允许在运行时执行一次性操作:例如数据库迁移、缓存清理或内容同步等命名的服务器端操作,你可以按需、按计划或从 CLI 运行这些操作
#选择加入实验性功能
Important
Tasks support is currently experimental. See nitrojs/nitro#1974 for the relevant discussion.
为了使用 tasks API,你需要启用实验性功能标志。Tasks 会从你的 serverDir 中扫描,同时也必须设置该配置:
import { defineConfig } from "nitro";
export default defineConfig({
serverDir: "./server",
experimental: {
tasks: true
}
})本页面上的所有示例都假设使用此配置。
#定义任务
可以在 serverDir 内的 tasks/[name].ts 文件中定义任务。
Note
与路由和插件一样,只有在设置了 serverDir(或 scanDirs)时才会扫描任务;默认不会扫描任何目录
支持嵌套目录。任务名称将使用 : 连接。
server/
tasks/
cleanup.ts <-- cleanup
db/
migrate.ts <-- db:migrate
nitro.config.ts示例:
import { defineTask } from "nitro/task";
export default defineTask({
meta: {
name: "db:migrate",
description: "Run database migrations",
},
run({ payload, context }) {
console.log("Running DB migration task...");
return { result: "Success" };
},
});#任务接口
defineTask 辅助函数接受一个具有以下属性的对象:
meta(可选):一个包含可选的name和description字符串字段的对象,用于在开发服务器和 CLI 中显示。run(必需):一个接收TaskEvent并返回(或解析为)一个包含可选result属性的对象的函数。
interface Task<RT = unknown> {
meta?: { name?: string; description?: string };
run(event: TaskEvent): { result?: RT } | Promise<{ result?: RT }>;
}#TaskEvent
run 函数接收一个具有以下属性的 TaskEvent 对象:
name:正在执行的任务的名称。payload:一个包含传递给任务的任何数据的对象(Record<string, unknown>)。context:一个TaskContext对象(根据运行时的不同,可能包含waitUntil)。
interface TaskEvent {
name: string;
payload: TaskPayload;
context: TaskContext;
}#通过配置注册任务
除了基于文件的扫描之外,还可以直接在 Nitro 配置中注册任务。这对于向扫描到的任务添加描述,或用于由模块提供并指向自定义处理程序路径的任务非常有用。
import { fileURLToPath } from "node:url";
import { defineConfig } from "nitro";
export default defineConfig({
serverDir: "./server",
experimental: {
tasks: true
},
tasks: {
// Describe a task scanned from `server/tasks/db/migrate.ts`
"db:migrate": {
description: "Run database migrations"
},
// Register a task from a custom location
"db:seed": {
handler: fileURLToPath(new URL("scripts/seed.ts", import.meta.url)),
description: "Seed the database"
}
}
})Warning
与路由处理程序不同,任务的 handler 会按原样导入,不会根据项目根目录解析,因此类似 "./scripts/seed.ts" 的路径会在构建时解析失败。请使用绝对路径(例如通过 fileURLToPath(new URL(..., import.meta.url))),或使用包名称
如果某个任务同时从 tasks/ 目录扫描到,并且在配置中定义,则配置中定义的 handler 优先级更高。
#定时任务
你可以使用 Nitro 配置定义定时任务,使其在指定的 cron 格式时间自动运行。
import { defineConfig } from "nitro";
export default defineConfig({
scheduledTasks: {
// 每分钟运行 `cms:update` 任务
'* * * * *': ['cms:update'],
// 运行单个任务(字符串简写形式)
'0 * * * *': 'db:cleanup'
}
})scheduledTasks 配置将 cron 表达式映射为单个任务名称(字符串)或任务名称数组。当多个任务被分配到同一个 cron 表达式时,它们会并行运行。
Tip
你可以使用 crontab.guru 轻松生成和理解 cron 表达式
当定时任务运行时,它会自动接收一个 payload,其中 scheduledTime 设置为当前时间戳(Date.now())。
Note
#平台支持
dev、node_server、node_cluster、node_middleware、bun和deno_server预设由 croner 引擎支持。cloudflare_module和cloudflare_pages预设原生集成了 Cron Triggers。Nitro 会在构建时自动在 wrangler 配置中生成 cron triggers,无需手动设置 wranglervercel预设原生集成了 Vercel Cron Jobs。Nitro 会在构建时自动生成 cron job 配置,无需手动设置vercel.json。你可以通过设置CRON_SECRET环境变量来保护 cron 端点- 计划支持更多预设(包括原生 primitives 支持)!
#waitUntil
在运行后台任务时,你可能需要确保服务器或工作进程等待任务完成。
根据运行时的不同,一个可选的 context.waitUntil 函数 可能 可用。
import { defineTask } from "nitro/task";
export default defineTask({
run({ context }) {
const promise = fetch(...)
context.waitUntil?.(promise);
await promise;
return { result: "Success" };
},
});#以编程方式运行任务
要手动运行任务,你可以使用 nitro/task 中的 runTask(name, { payload?, context? }) 函数。
示例:
import { defineHandler } from "nitro";
import { runTask } from "nitro/task";
export default defineHandler(async (event) => {
// 重要:验证用户身份并验证 payload!
const payload = Object.fromEntries(event.url.searchParams);
const { result } = await runTask("db:migrate", { payload });
return { result };
});#错误处理
runTask 在以下情况下会抛出 HTTP 错误:
- 任务不存在(状态
404)。 - 任务没有处理程序实现(状态
501)。
在任务的 run 函数中抛出的任何错误都会传播给调用者。
#使用开发服务器运行任务
Nitro 的内置开发服务器公开了任务,以便无需编程即可轻松执行。
#使用 API 路由
#/_nitro/tasks
此端点返回可用任务名称及其元数据的列表。
// [GET] /_nitro/tasks
{
"tasks": {
"db:migrate": {
"description": "Run database migrations"
},
"cms:update": {
"description": "Update CMS content"
}
},
"scheduledTasks": [
{
"cron": "* * * * *",
"tasks": [
"cms:update"
]
}
]
}#/_nitro/tasks/:name
此端点执行任务。你可以使用查询参数和 JSON 请求体来提供 payload。在 JSON 请求体中发送的 payload 必须位于 "payload" 属性下。
import { defineTask } from "nitro/task";
export default defineTask({
meta: {
name: "echo:payload",
description: "Returns the provided payload",
},
run({ payload, context }) {
console.log("Running echo task...");
return { result: payload };
},
});Note
JSON 请求体中指定的键会覆盖查询参数中存在的任何值
#使用 CLI
Important
只有在 dev 服务器正在运行 时才能运行这些命令。你应该在第二个终端中运行它们
#列出任务
nitro task list#运行任务
nitro task run db:migrate --payload "{}"--payload 标志接受一个 JSON 字符串,该字符串将被解析并传递给任务。如果该值不是有效的 JSON 对象,任务将在没有 payload 的情况下运行。
#注意事项
#并发
任务运行会按任务名称去重:每个任务在每个服务器实例中最多只能有一个正在运行的实例。对已在运行的任务调用 runTask 不会启动新的运行:所有并发调用者,即使传入不同的 payload,也会共享第一个正在运行的任务结果