 到 trigger.config.ts 的持久化任务实战)
AI Agent后端任务调度开发工具可观测性AI 应用【免费下载链接】trigger.devTrigger.dev – build and deploy durable AI agents and workflows项目地址https://gitcode.com/gh_mirrors/tr/trigger.dev点击查看免费下载Trigger.dev 的核心抽象是任务Task——一种可以长时间运行、对失败具备强韧性的函数。本指南以trigger.dev/sdk技能文档trigger-authoring-tasks为骨架系统讲解如何在/trigger目录下用task()/schemaTask()定义任务并覆盖重试策略、Result 结果形态、幂等键、持久等待wait、运行元数据、cron 定时任务、队列与并发控制以及trigger.config.ts配置文件的要点。读完本文你将掌握编写、触发、调试与配置 Trigger.dev 后端任务的一整套实战能力并清楚哪些是新手最容易踩的坑。版本固定的权威参考先找到你的完整技能文档本仓库在 packages/cli-v3/skills/trigger-authoring-tasks/SKILL.md 提供了一个入口技能文件它的完整版含全部sources文档清单位于 packages/trigger-sdk/skills/trigger-authoring-tasks/SKILL.md。核心原则完整的、版本钉死的任务编写参考随你安装的trigger.dev/sdk一起发布。在你自己的项目里它位于node_modules/trigger.dev/sdk/skills/trigger-authoring-tasks/SKILL.md—— 完整指南setup、schemaTask、重试、触发与 Result 形态、幂等、等待、元数据、定时任务、队列/并发、trigger.config.tsnode_modules/trigger.dev/sdk/docs/—— 与该 SDK 版本完全对应的全套文档技能文件的sources:frontmatter 列出了它引用的每一页。需要检索某个 API 时可以直接在本地 grep例如grep -rl schemaTask node_modules/trigger.dev/sdk/docs/如果上述路径不存在说明trigger.dev/sdk尚未安装需要先安装。在非 hoisted未提升的依赖布局下可以用下面命令解析包的真实位置再在其旁读取skills/与docs/node -p require.resolve(trigger.dev/sdk/package.json)由于技能与文档直接从node_modules读取它们始终与项目里实际使用的 SDK 版本一致不会出现文档漂移。仓库内对应的文档源可参考 docs/tasks/overview.mdx、docs/triggering.mdx 与 docs/config/config-file.mdx。导入约定永远从trigger.dev/sdk导入绝不使用已废弃的别名trigger.dev/sdk/v3也不要从trigger.dev/core导入。从源码看trigger.dev/sdk的入口 packages/trigger-sdk/src/v3/tasks.ts 直接导出task createTask、schemaTask createSchemaTask以及tasks命名空间是唯一受支持的入口。起步定义第一个任务任务定义在项目/trigger目录下的文件中。每个任务通过task({...})创建id在项目内必须唯一// /trigger/hello-world.ts import { task } from trigger.dev/sdk; export const helloWorld task({ id: hello-world, // 项目内唯一 run: async (payload: { message: string }, { ctx }) { console.log(payload.message, attempt, ctx.attempt.number); return { ok: true }; // 返回值必须是 JSON 可序列化的 }, });run函数接收两个参数payload—— 触发时传入的任务负载第二个参数 —— 包含ctx运行上下文例如ctx.attempt.number表示当前是第几次尝试、一个 abortsignal用于响应取消以及一个已废弃的init输出。函数的返回值就是任务输出必须 JSON 可序列化数组、对象、字符串、数字、布尔值等因为任务输出需要被平台持久化存储。核心模式一用schemaTask校验负载schemaTask在task基础上增加schema校验。schema接受 Zod / Yup / Superstruct / ArkType / valibot / typebox 解析器也可以是一个自定义的(data: unknown) T函数import { schemaTask } from trigger.dev/sdk; import { z } from zod; export const createUser schemaTask({ id: create-user, schema: z.object({ name: z.string(), age: z.number() }), run: async (payload) ({ greeting: Hi ${payload.name} }), });校验失败时会抛出TaskPayloadParsedError并且不会触发重试——因为问题出在输入数据本身重试没有意义。从源码看TaskPayloadParsedError在 packages/core/src/v3/errors.ts 中定义携带原始cause任务的执行器在 packages/core/src/v3/workers/taskExecutor.ts 处捕获解析错误后抛出该异常。createSchemaTask的实现位于 packages/trigger-sdk/src/v3/shared.ts。核心模式二配置重试与提前终止默认情况下maxAttempts最大尝试次数为3。你可以通过任务级retry覆盖配置文件中的默认值import { task, AbortTaskRunError } from trigger.dev/sdk; export const charge task({ id: charge, retry: { maxAttempts: 5, factor: 1.8, minTimeoutInMs: 500, maxTimeoutInMs: 30_000, randomize: true }, run: async (payload: { amount: number }) { if (payload.amount 0) throw new AbortTaskRunError(Invalid amount); // 不再重试 // 可能抛错并触发重试的工作 }, });要点AbortTaskRunError抛出它即可立即停止重试例如业务上判定参数非法、继续重试无意义。该错误类定义在 packages/core/src/v3/errors.ts。retry字段maxAttempts最大尝试次数、factor退避增长因子、minTimeoutInMs/maxTimeoutInMs退避上下限、randomize是否随机抖动避免惊群。catchError需要更精细控制时可以配置catchError: async ({ payload, error, ctx, retryAt }) {...}返回{ skipRetrying: true }跳过重试、{ retryAt: Date }指定下次重试时间或返回undefined走正常逻辑。任务内重试retry.onThrow、retry.fetch等 API 支持在任务内部对局部代码片段做重试。更完整的重试语义可参考 docs/errors-retrying.mdx。核心模式三触发另一个任务并处理 Result 形态在任务内部触发另一个任务用yourTask.triggerAndWait(payload)。返回值是一个 Result 对象而不是裸输出你必须检查.ok或调用.unwrap()在失败时直接抛错export const parentTask task({ id: parent-task, run: async () { const result await childTask.triggerAndWait({ data: x }); if (result.ok) return result.output; // 类型化的子任务输出 console.error(child failed, result.error); // 或者const output await childTask.triggerAndWait({ data: x }).unwrap(); }, });失败时SubtaskUnwrapError会携带runId、taskId和cause信息便于追踪失败来源。扇出fan-out用childTask.batchTriggerAndWait([{ payload: a }, { payload: b }])返回结果的.runs数组每一项形如{ ok, id, output?, error?, taskIdentifier }。从源码看triggerAndWait/batchTriggerAndWait/triggerAndSubscribe均通过tasks命名空间暴露packages/trigger-sdk/src/v3/tasks.tstriggerAndWait返回的是TaskRunPromisepackages/trigger-sdk/src/v3/shared.ts其.ok/.unwrap()语义正对应 Result 形态。核心模式四从后端代码触发任务type-only 导入在任务之外例如 Remix / Next.js 的路由处理器、webhook、定时脚本触发任务时只导入任务类型按 id 触发绝不要把任务实例打进后端 bundleimport { tasks } from trigger.dev/sdk; import type { emailSequence } from ~/trigger/emails; const handle await tasks.triggertypeof emailSequence( email-sequence, { to: ab.com, name: Ada }, { delay: 1h } );tasks.triggerTaskType(id, payload, options)的泛型参数传入typeof taskInstance即可获得负载与输出的类型推断。批量触发可以使用tasks.batchTrigger以及batch.trigger([{ id, payload }])。触发选项TriggerOptions包括delay延迟执行、ttl运行生存期、idempotencyKey幂等键、idempotencyKeyTTL幂等键有效期、debounce防抖、queue指定队列、concurrencyKey并发键、maxAttempts覆盖最大尝试次数、tags打标签、metadata初始元数据、priority优先级、region区域和machine机器规格。运行管理用runs.retrieve查看运行详情、runs.cancel取消运行、runs.reschedule重新调度。参见 docs/triggering.mdx。核心模式五幂等键Idempotency KeysidempotencyKeys.create(key, { scope })返回一个64 字符的哈希键配合触发时的idempotencyKey选项使用import { idempotencyKeys, task } from trigger.dev/sdk; export const processOrder task({ id: process-order, run: async (payload: { orderId: string; email: string }) { const key await idempotencyKeys.create(confirm-${payload.orderId}); await sendEmail.trigger({ to: payload.email }, { idempotencyKey: key }); }, });作用域scope语义需要注意版本差异从v4.3.1起裸字符串键默认作用域为run即同一次运行内去重若要“全项目只执行一次”once-ever必须显式指定scope: globalv4.3.0 及更早版本中裸字符串键的行为是全局性的升级后行为会变化不要把旧习惯带进新代码。SDK 侧封装位于 packages/trigger-sdk/src/v3/idempotencyKeys.ts底层实现createIdempotencyKey/resetIdempotencyKey来自trigger.dev/core/v3。完整说明见 docs/idempotency.mdx。核心模式六持久等待与运行元数据持久等待让任务“睡”过去且不占计算资源进程重启后依然能恢复import { task, metadata, wait } from trigger.dev/sdk; export const importer task({ id: importer, run: async (payload: { rows: unknown[] }) { metadata.set(status, processing).set(total, payload.rows.length); await wait.for({ seconds: 5 }); metadata.set(status, complete); }, });wait.for({ seconds })按时长等待wait.until({ date })等到某个时刻。从 packages/trigger-sdk/src/v3/wait.ts 的源码可以看到一个重要的细节小于等于 5 秒DURATION_WAIT_CHARGE_THRESHOLD_MS 5000的等待会直接在当前进程中setTimeout并计入计算用量会打印警告超过 5 秒的等待才走服务端 waitpoint实现真正不占资源的持久等待。wait.forToken只能从任务run()内部调用源码中会检查taskContext.ctx否则抛错相关 API 还有wait.createToken、wait.completeToken。运行元数据metadatametadata.*只能在run()内部读写在模块作用域或无关后端代码里调用是无效操作get返回undefined。更新是同步且可链式的支持set、del、replace、append、remove、increment、decrement。SDK 侧实现见 packages/trigger-sdk/src/v3/metadata.ts。关于元数据的边界条件最大 256KB超限会报错不会自动传播给子任务子任务有自己独立的元数据父任务需要显式通过触发选项{ metadata: metadata.current() }传递向父级/根级传递用metadata.parent.*/metadata.root.*metadata.stream自 4.1.0 起已废弃改用streams.pipe()。人工介入Human-in-the-loopwait.createToken({ timeout, tags })返回{ id, url, publicAccessToken, ... }把url发给人工处理任务内用wait.forTokenT(token: string | { id: string })等待返回{ ok, output?, error? }也可.unwrap()处理完成后在外部用wait.completeToken(tokenId, output)提交结果。相关文档docs/wait.mdx、docs/wait-for.mdx、docs/wait-until.mdx、docs/wait-for-token.mdx。核心模式七定时cron任务trigger.dev/sdk的schedules命名空间提供了schedules.task来声明定时任务import { schedules } from trigger.dev/sdk; export const dailyReport schedules.task({ id: daily-report, cron: { pattern: 0 5 * * *, timezone: Asia/Tokyo }, run: async (payload) { console.log(scheduled at, payload.timestamp, next, payload.upcoming); }, });定时任务的负载payload包含timestamp本次触发时间、lastTimestamp上次触发时间、timezone、scheduleId、externalId和upcoming下一次触发时间。除了声明式 cron还可以动态创建调度schedules.create({ task, cron, timezone?, externalId?, deduplicationKey })其中deduplicationKey必填且按项目维度去重。管理 API 还有retrieve / list / update / activate / deactivate / del / timezonestimezones默认包含UTC且排在最前可用{ excludeUtc: true }排除。源码实现见 packages/trigger-sdk/src/v3/schedules/index.tsschedules.task与 packages/trigger-sdk/src/v3/schedules/index.tsschedules.create。完整文档见 docs/tasks/scheduled.mdx。核心模式八队列与并发在任务上声明queue: { concurrencyLimit }或定义一个队列并让多个任务共享import { queue, task } from trigger.dev/sdk; export const emails queue({ name: emails, concurrencyLimit: 5 }); export const sendEmail task({ id: send-email, queue: emails, run: async () {} });触发时覆盖队列{ queue: queue-name }可以按触发动态指定队列每租户队列配合concurrencyKey实现例如按userId隔离并发队列管理queues.list / retrieve / pause / resume / overrideConcurrencyLimit / resetConcurrencyLimit见 packages/trigger-sdk/src/v3/queues.ts。从源码注释可以读到一条重要的演进信息packages/trigger-sdk/src/v3/queues.ts“队列级并发”是遗留模型——现代模型中队列只是运行排队的有序线路并发在任务上声明并通过concurrencyLimits管理对新模型队列调用旧的队列级并发 API 会被服务端拒绝应改用concurrencyLimits.reset(task/my-task)迁移。相关文档docs/queues.mdx、docs/management/queues 与 docs/concurrency.mdx。核心模式九trigger.config.ts要点defineConfig是 SDK 导出的纯函数源码见 packages/trigger-sdk/src/v3/config.ts直接返回传入的配置对象import { defineConfig } from trigger.dev/sdk; export default defineConfig({ project: project ref, dirs: [./trigger], machine: small-1x, retries: { enabledInDev: false, default: { maxAttempts: 3, factor: 2, minTimeoutInMs: 1000, maxTimeoutInMs: 10000, randomize: true }, }, });project项目引用project ref指定任务归属的 Trigger.dev 项目dirs任务源码目录数组默认[./trigger]machine运行机器规格例如small-1xretries全局重试默认值enabledInDev控制本地开发时是否启用重试任务级retry会覆盖这里的默认值build.external控制哪些包不进入 bundle。对于sharp、re2、sqlite3这类原生native模块以及 WASM 包必须加入build.external否则默认打包会失败或产生无法运行的产物构建扩展Build extensionsadditionalFiles、prismaExtension、puppeteer、playwright、ffmpeg、pythonExtension、aptGet、syncEnvVars等均来自trigger.dev/build包每个扩展都有自己的配置文档全部随 SDK 打包在trigger.dev/sdk/docs/config/extensions/先从overview.mdx看起。接入扩展前先读对应文档而不是凭猜测写 APItelemetry配置 OpenTelemetry 插桩instrumentations与导出器exporters。日志、追踪与指标推荐使用 SDK 内置的logger对象生成结构化日志便于在运行日志中检索import { task, logger } from trigger.dev/sdk; export const loggingExample task({ id: logging-example, run: async (payload: { data: Recordstring, string }) { // 第一个参数是消息第二个参数必须是键值对象Recordstring, unknown logger.debug(Debug message, payload.data); logger.log(Log message, payload.data); logger.info(Info message, payload.data); logger.warn(Youve been warned, payload.data); logger.error(Error message, payload.data); }, });自定义 spanlogger.trace(name, async (span) {...})创建一个 OpenTelemetry trace可在 span 上设置属性并返回值const user await logger.trace(fetch-user, async (span) { span.setAttribute(user.id, 1); // ...do stuff return { id: 1, name: John Doe, fetchedAt: new Date() }; });模块级指标import { otel } from trigger.dev/sdk后用otel.metrics.getMeter(name)获取 meter再创建 Counter / Histogram / UpDownCounter 等自定义指标。注意instrument 要在模块级任务run函数之外创建一次以便跨多次运行复用。指标可在控制台 Dashboards 查看、用 TRQL 查询并通过 telemetry exporters 导出到外部服务。console.log()/console.error()等标准日志也会出现在运行日志中任何函数/包产生的日志同样可见。任务运行日志由 logs、traces 和 spans 组成详细说明见 docs/logging.mdx。常见错误清单务必逐条对照致命错误把等待结果当成裸输出。triggerAndWait和wait.forToken返回的是 Result 对象不是原始输出。错误const out await childTask.triggerAndWait(p); use(out.foo);正确const r await childTask.triggerAndWait(p); if (r.ok) use(r.output.foo);或.unwrap()。把triggerAndWait/batchTriggerAndWait/wait包进Promise.all。错误await Promise.all([childTask.triggerAndWait(a), childTask.triggerAndWait(b)]);正确await childTask.batchTriggerAndWait([{ payload: a }, { payload: b }]);或顺序 for 循环。在后端代码中导入任务实例。错误在路由处理器里import { emailSequence } from ~/trigger/emails;正确import type { emailSequence }加上tasks.triggertypeof emailSequence(email-sequence, payload)。在run()之外调用metadata.set/get。错误在模块作用域或无关后端代码中设置元数据这是无效操作get返回undefined。正确只在run()或任务生命周期钩子如onStartAttempt内调用。假设子任务继承父任务的队列或元数据。错误期望子任务共享父任务的concurrencyLimit或能看到父任务元数据。正确子任务跑在自己的队列上通过{ metadata: metadata.current() }显式传递元数据或用metadata.parent.*向上推送。把原生/WASM 包打进默认 bundle。错误把sharp、re2、sqlite3或 WASM 包留在默认 bundle 中。正确在trigger.config.ts的build.external中声明它们。依赖裸字符串幂等键的全局性。错误trigger(p, { idempotencyKey: welcome-email })期望“只执行一次”该行为仅在 v4.3.0 及更早版本成立。正确await idempotencyKeys.create(welcome-email, { scope: global })。相关资源任务编写只是 Trigger.dev 技能体系的一部分与其并行的还有trigger-realtime-and-frontend—— 用 React hooks 订阅运行状态、从前端触发任务packages/trigger-sdk/skills/trigger-realtime-and-frontend/SKILL.mdtrigger-authoring-chat-agent与trigger-chat-agent-advanced—— 构建 AI 聊天 Agentpackages/trigger-sdk/skills/trigger-authoring-chat-agent/SKILL.md、packages/trigger-sdk/skills/trigger-chat-agent-advanced/SKILL.md。对应文档始终与技能文件一同发布在trigger.dev/sdk/docs/下建议按以下顺序阅读docs/tasks/overview.mdx→docs/triggering.mdx→docs/config/config-file.mdx。本仓库中的任务文档源码可参考 docs/tasks/overview.mdx、docs/tasks/schemaTask.mdx、docs/tasks/scheduled.mdx、docs/context.mdx 与 docs/runs/metadata.mdx。赞分享AI Agent后端任务调度开发工具可观测性AI 应用【免费下载链接】trigger.devTrigger.dev – build and deploy durable AI agents and workflows项目地址https://gitcode.com/gh_mirrors/tr/trigger.dev点击查看免费下载相关推荐Trigger.dev任务编写指南从基础到高级技巧Trigger.dev任务编写指南从基础到高级技巧 本文全面介绍Trigger.dev任务编写的各个方面从基础的任务定义与配置参数详解开始深入解析任务基本AI Agent后端任务调度开发工具可观测性AI 应用3 行代码给图片加上隐形水印blind_watermark 盲水印上手3 行代码给图片加上隐形水印blind_watermark 盲水印上手 有没有遇到过这种情况作品刚发上网就被别人转载、裁剪、压缩后到处传播署名被删得干干DevOpsCLITrigger.dev任务队列持久化终极指南如何确保系统重启后任务不丢失的10个关键策略Trigger.dev任务队列持久化终极指南如何确保系统重启后任务不丢失的10个关键策略 在构建可靠的异步任务系统时任务队列持久化是最关键的挑战之一。当系统AI Agent后端任务调度开发工具可观测性AI 应用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考