Skip to main content

trigger-tasks

Covers writing backend Trigger.dev tasks with @trigger.dev/sdk: defining task() and schemaTask(), the run function and its ctx, retries, waits, queues and concurrency, idempotency keys, run metadata, logging, triggering other tasks (and the Result shape), scheduled/cron tasks, and the essentials of trigger.config.ts. Load this whenever you are authoring or editing code inside a /trigger directory, defining a task, or writing backend code that triggers tasks. Realtime/React hooks and AI chat are covered by separate skills.

معلومات المصدر

المستودع
triggerdotdev/skills
آخر نشاط في المصدر
١٢ أغسطس ٢٠٢٦ في ١١:٣٦
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٣٤
التفرعات
٧

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
trigger-tasks
description
Covers writing backend Trigger.dev tasks with @trigger.dev/sdk: defining task() and schemaTask(), the run function and its ctx, retries, waits, queues and concurrency, idempotency keys, run metadata, logging, triggering other tasks (and the Result shape), scheduled/cron tasks, and the essentials of trigger.config.ts. Load this whenever you are authoring or editing code inside a /trigger directory, defining a task, or writing backend code that triggers tasks. Realtime/React hooks and AI chat are covered by separate skills.
type
core
library
trigger.dev
sources
["docs/tasks/overview.mdx","docs/tasks/schemaTask.mdx","docs/tasks/scheduled.mdx","docs/triggering.mdx","docs/queue-concurrency.mdx","docs/idempotency.mdx","docs/runs/metadata.mdx","docs/logging.mdx","docs/errors-retrying.mdx","docs/wait.mdx","docs/wait-for.mdx","docs/wait-until.mdx","docs/wait-for-token.mdx","docs/context.mdx","docs/config/config-file.mdx"]
# Authoring Trigger.dev Tasks Tasks are functions that can run for a long time with strong resilience to failure. Define them in files under your `/trigger` directory. Always import from `@trigger.dev/sdk`. Never import from `@trigger.dev/sdk/v3` (deprecated alias) or `@trigger.dev/core`. ## Setup ```ts // /trigger/hello-world.ts import { task } from "@trigger.dev/sdk"; export const helloWorld = task({ id: "hello-world", // unique within the project run: async (payload: { message: string }, { ctx }) => { console.log(payload.message, "attempt", ctx.attempt.number); return { ok: true }; // must be JSON serializable }, }); ``` The `run` function receives the payload and a second argument with `ctx` (run context), an abort `signal`, and a deprecated `init` output. The return value is the task output and must be JSON serializable. ## Core patterns ### 1. Validate the payload with `schemaTask` `schema` accepts a Zod / Yup / Superstruct / ArkType / valibot / typebox parser or a custom `(data: unknown) => T` function. A validation failure throws `TaskPayloadParsedError` and skips retrying. ```ts 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}` }), }); ``` ### 2. Configure retries and abort early The default `maxAttempts` is 3. Throw `AbortTaskRunError` to stop retrying immediately. Task-level `retry` overrides the config-file defaults. ```ts 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"); // no retry // work that may throw and retry }, }); ``` For finer control, `catchError: async ({ payload, error, ctx, retryAt }) => {...}` can return `{ skipRetrying: true }`, `{ retryAt: Date }`, or `undefined` (use normal logic). `retry.onThrow`, `retry.fetch`, also exist for in-task retrying. ### 3. Trigger another task and handle the Result From inside a task use `yourTask.triggerAndWait(payload)`. The result is a Result object that you must check (`ok`), or `.unwrap()` to throw on failure. ```ts export const parentTask = task({ id: "parent-task", run: async () => { const result = await childTask.triggerAndWait({ data: "x" }); if (result.ok) return result.output; // typed child output console.error("child failed", result.error); // or: const output = await childTask.triggerAndWait({ data: "x" }).unwrap(); }, }); ``` `SubtaskUnwrapError` carries `runId`, `taskId`, and `cause`. For fan-out use `childTask.batchTriggerAndWait([{ payload: a }, { payload: b }])`; the result has a `.runs` array, each entry `{ ok, id, output?, error?, taskIdentifier }`. ### 4. Trigger from backend code with a type-only import Outside a task, import the task type only and trigger by id. Do not import the task instance into backend bundles. ```ts import { tasks } from "@trigger.dev/sdk"; import type { emailSequence } from "~/trigger/emails"; const handle = await tasks.trigger<typeof emailSequence>( "email-sequence", { to: "a@b.com", name: "Ada" }, { delay: "1h" } ); ``` `tasks.batchTrigger` and `batch.trigger([{ id, payload }])` cover batches. Trigger options include `delay`, `ttl`, `idempotencyKey`, `idempotencyKeyTTL`, `debounce`, `queue`, `concurrencyKey`, `maxAttempts`, `tags`, `metadata`, `priority`, `region`, and `machine`. Inspect runs with `runs.retrieve`, `runs.cancel`, and `runs.reschedule`. ### 5. Idempotency keys `idempotencyKeys.create(key, { scope })` returns a 64-char hashed key. A raw string key defaults to `"run"` scope (v4.3.1+); for once-ever behavior use `scope: "global"`. ```ts 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 }); }, }); ``` ### 6. Waits and run metadata `wait.for({ seconds })` and `wait.until({ date })` durably pause the run. `metadata.*` is readable and writable only inside `run()`; updates are synchronous and chainable (`set`, `del`, `replace`, `append`, `remove`, `increment`, `decrement`). ```ts 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"); }, }); ``` For human-in-the-loop, `wait.createToken({ timeout, tags })` returns `{ id, url, publicAccessToken, ... }`; resume with `wait.forToken<T>(token: string | { id: string })` which returns `{ ok, output?, error? }` (or `.unwrap()`), and complete it elsewhere with `wait.completeToken(tokenId, output)`. Metadata max is 256KB and is not propagated to child tasks; push values to a parent with `metadata.parent.*` / `metadata.root.*`. (`metadata.stream` is deprecated since 4.1.0 in favor of `streams.pipe()`.) ### 7. Scheduled (cron) tasks ```ts 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); }, }); ``` The payload includes `timestamp`, `lastTimestamp`, `timezone`, `scheduleId`, `externalId`, and `upcoming`. Attach schedules dynamically with `schedules.create({ task, cron, timezone?, externalId?, deduplicationKey })` (the dedup key is required and per-project), plus `retrieve / list / update / activate / deactivate / del / timezones`. ### 8. Queues and concurrency Set `queue: { concurrencyLimit }` on a task, or share a queue across tasks: ```ts 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 () => {} }); ``` At trigger time override with `{ queue: "queue-name" }` and add `concurrencyKey` for per-tenant queues. Manage queues with `queues.list / retrieve / pause / resume / overrideConcurrencyLimit / resetConcurrencyLimit`. ### 9. `trigger.config.ts` essentials ```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 }, }, }); ``` `build.external` controls which packages stay out of the bundle. Build extensions (`additionalFiles`, `prismaExtension`, `puppeteer`, `playwright`, `ffmpeg`, `pythonExtension`, `aptGet`, `syncEnvVars`, etc.) come from `@trigger.dev/build`. `telemetry` configures instrumentations and exporters. Each extension has its own setup doc, all bundled under `@trigger.dev/sdk/docs/config/extensions/` (start with `overview.mdx`); read the one you need before wiring it up rather than guessing the API. ### Logging `logger.debug / log / info / warn / error(message, dataRecord?)` write structured logs; `logger.trace(name, async (span) => {...})` adds a span. Module-level metrics use `otel.metrics.getMeter(name)`. ## Common mistakes 1. **CRITICAL: Treating the wait result as the output.** `triggerAndWait` and `wait.forToken` return a Result object, not the raw output. - Wrong: `const out = await childTask.triggerAndWait(p); use(out.foo);` - Correct: `const r = await childTask.triggerAndWait(p); if (r.ok) use(r.output.foo);` (or `.unwrap()`). 2. **Wrapping `triggerAndWait` / `batchTriggerAndWait` / `wait` in `Promise.all`.** - Wrong: `await Promise.all([childTask.triggerAndWait(a), childTask.triggerAndWait(b)]);` - Correct: `await childTask.batchTriggerAndWait([{ payload: a }, { payload: b }]);` (or a sequential for-loop). 3. **Importing the task instance into backend code.** - Wrong: `import { emailSequence } from "~/trigger/emails";` in a route handler. - Correct: `import type { emailSequence }` plus `tasks.trigger<typeof emailSequence>("email-sequence", payload)`. 4. **Calling `metadata.set/get` outside `run()`.** - Wrong: setting metadata at module scope or in unrelated backend code (a no-op; `get` returns `undefined`). - Correct: call inside `run()` or a task lifecycle hook. 5. **Assuming child tasks inherit the parent's queue or metadata.** - Wrong: expecting a subtask to share the parent's `concurrencyLimit` or see its metadata. - Correct: subtasks run on their own queue; pass metadata explicitly via `{ metadata: metadata.current() }`, or push up with `metadata.parent.*`. 6. **Bundling native/WASM packages.** - Wrong: leaving `sharp`, `re2`, `sqlite3`, or WASM packages in the default bundle. - Correct: add them to `build.external` in `trigger.config.ts`. 7. **Relying on a raw string idempotency key being global.** - Wrong: `trigger(p, { idempotencyKey: "welcome-email" })` expecting once-ever (true only in v4.3.0 and earlier). - Correct: `await idempotencyKeys.create("welcome-email", { scope: "global" })`. ## References Sibling skills: - **trigger-realtime** for subscribing to runs and triggering from the frontend with React hooks. - **trigger-authoring-chat-agent** and **trigger-chat-agent-advanced** for building AI chat agents. Reference docs ship beside this skill in the same package, read them locally (no network), pinned to your installed version. The `sources:` frontmatter above lists every doc this skill draws from, all under `@trigger.dev/sdk/docs/`. Start with: - `@trigger.dev/sdk/docs/tasks/overview.mdx` - `@trigger.dev/sdk/docs/triggering.mdx` - `@trigger.dev/sdk/docs/config/config-file.mdx` ## Version This skill is bundled inside `@trigger.dev/sdk` and read directly from `node_modules`, so it always matches your installed SDK version (see the adjacent `package.json`). The full documentation for these APIs ships alongside it under `@trigger.dev/sdk/docs/`.
عرض على GitHub