mcpField
T
trigger-tasks

trigger-tasks

github.com/triggerdotdev開発353.2k 回インストール1 週間前に更新
リポジトリ

trigger-tasks について

Trigger.dev SDK で永続的なバックグラウンドタスクを作成する開発者向けスキルです。タスク定義、リトライ、スケジュール、キュー、待機、タスクの連携を説明し、よくある実装上の注意点も扱います。

主な機能

  1. 01タスクの定義と検証
  2. 02リトライと冪等性の設定
  3. 03タスクの起動とバッチ処理
  4. 04cron によるタスクのスケジュール
  5. 05キューと並行処理の管理
  6. 06永続的な待機と実行メタデータ

活用シーン

  1. 01耐障害性のある長時間バックグラウンドジョブの構築
  2. 02親タスクと子タスクの実行連携
  3. 03定期レポートのスケジュール
  4. 04複数タスク間の並行処理の制限

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/triggerdotdev/skills --skill trigger-tasks

インストール後、Claude Code で/trigger-tasksを入力して読み込まれたか確認します。

詳細

Trigger.dev タスクの作成

タスクは、強い障害耐性を備え、長時間実行できる関数です。/trigger ディレクトリ内のファイルで定義します。必ず @trigger.dev/sdk からインポートしてください。@trigger.dev/sdk/v3(非推奨のエイリアス)や @trigger.dev/core からはインポートしないでください。

セットアップ

// /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
  },
});

run 関数は、ペイロードと、ctx(実行コンテキスト)、中断用の signal、非推奨の init 出力を含む第 2 引数を受け取ります。戻り値はタスクの出力であり、JSON にシリアライズ可能でなければなりません。

基本的なパターン

1. schemaTask でペイロードを検証する

schema には、Zod/Yup/Superstruct/ArkType/valibot/typebox のパーサー、またはカスタムの (data: unknown) => T 関数を指定できます。検証に失敗すると TaskPayloadParsedError がスローされ、再試行は行われません。

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. 再試行を設定し、早期に中断する

デフォルトの maxAttempts は 3 です。AbortTaskRunError をスローすると、すぐに再試行を停止します。タスクレベルの 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"); // no retry
    // work that may throw and retry
  },
});

より細かく制御するには、catchError: async ({ payload, error, ctx, retryAt }) => {...} から { skipRetrying: true }、{ retryAt: Date }、または undefined(通常のロジックを使用)を返せます。タスク内で再試行するための retry.onThrow と retry.fetch もあります。

3. 別のタスクをトリガーし、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; // typed child output
    console.error("child failed", result.error);
    // or: const output = await childTask.triggerAndWait({ data: "x" }).unwrap();
  },
});

SubtaskUnwrapError には runId、taskId、cause が含まれます。ファンアウトには childTask.batchTriggerAndWait([{ payload: a }, { payload: b }]) を使用します。結果には .runs 配列があり、各エントリは { ok, id, output?, error?, taskIdentifier } です。

4. 型のみのインポートでバックエンドコードからトリガーする

タスクの外部では、タスクの型のみをインポートし、ID を指定してトリガーします。バックエンドのバンドルにはタスクインスタンスをインポートしないでください。

import { tasks } from "@trigger.dev/sdk";
import type { emailSequence } from "~/trigger/emails";

const handle = await tasks.trigger<typeof emailSequence>(
  "email-sequence",
  { to: "[email protected]", name: "Ada" },
  { delay: "1h" }
);

tasks.batchTrigger と batch.trigger([{ id, payload }]) でバッチ処理を実行できます。トリガーオプションには、delay、ttl、idempotencyKey、idempotencyKeyTTL、debounce、queue、concurrencyKey、maxAttempts、tags、metadata、priority、region、machine があります。実行を確認するには、runs.retrieve、runs.cancel、runs.reschedule を使用します。

5. 冪等性キー

idempotencyKeys.create(key, { scope }) は、64 文字のハッシュ化されたキーを返します。文字列のキーを指定すると、デフォルトでスコープは "run" になります(v4.3.1 以降)。一度限りの動作にするには、scope: "global" を使用します。

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. 待機と実行メタデータ

wait.for({ seconds }) と wait.until({ date }) は、実行を永続的に一時停止します。metadata.* は run() 内でのみ読み書きでき、更新は同期的に行われ、チェーンできます(set、del、replace、append、remove、increment、decrement)。

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.createToken({ timeout, tags }) が { id, url, publicAccessToken, ... } を返します。wait.forToken<T>(token: string | { id: string }) で再開すると { ok, output?, error? } が返されます(または .unwrap() を使用できます)。別の場所で wait.completeToken(tokenId, output) を使って完了させます。メタデータの最大サイズは 256KB で、子タスクには引き継がれません。親タスクに値を渡すには metadata.parent.*/metadata.root.* を使用します。(metadata.stream は 4.1.0 以降非推奨で、代わりに streams.pipe() を使用してください。)

7. スケジュール(cron)タスク
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);
  },
});

ペイロードには timestamp、lastTimestamp、timezone、scheduleId、externalId、upcoming が含まれます。schedules.create({ task, cron, timezone?, externalId?, deduplicationKey }) でスケジュールを動的に追加できます(重複排除キーは必須で、プロジェクトごとに設定します)。また、retrieve/list/update/activate/deactivate/del/timezones を使用できます。

8. キューと並行処理

タスクに 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 を追加します。キューの管理には queues.list/retrieve/pause/resume/overrideConcurrencyLimit/resetConcurrencyLimit を使用します。

9. trigger.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 },
  },
});

build.external は、バンドルに含めないパッケージを制御します。ビルド拡張機能(additionalFiles、prismaExtension、puppeteer、playwright、ffmpeg、pythonExtension、aptGet、syncEnvVars など)は、@trigger.dev/build に含まれています。telemetry はインストルメンテーションとエクスポーターを設定します。各拡張機能には専用のセットアップドキュメントがあり、すべて @trigger.dev/sdk/docs/config/extensions/ にまとめられています(overview.mdx から始めてください)。API を推測して接続するのではなく、必要なドキュメントを読んでから設定してください。

ロギング

logger.debug / log / info / warn / error(message, dataRecord?) は構造化ログを書き込みます。logger.trace(name, async (span) => {...}) はスパンを追加します。モジュールレベルのメトリクスには otel.metrics.getMeter(name) を使用します。

よくある間違い

  1. 重大:待機結果を出力として扱う。 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())。
  2. triggerAndWait/batchTriggerAndWait/wait を Promise.all でラップする。

    • 誤り:await Promise.all([childTask.triggerAndWait(a), childTask.triggerAndWait(b)]);
    • 正しい:await childTask.batchTriggerAndWait([{ payload: a }, { payload: b }]);(または順次実行する for ループ)。
  3. バックエンドコードにタスクインスタンスをインポートする。

    • 誤り:ルートハンドラー内で import { emailSequence } from "~/trigger/emails";。
    • 正しい:import type { emailSequence } を使い、さらに tasks.trigger<typeof emailSequence>("email-sequence", payload) を呼び出します。
  4. run() の外で metadata.set/get を呼び出す。

    • 誤り:モジュールスコープや無関係なバックエンドコードでメタデータを設定する(何も起こらず、get は undefined を返します)。
    • 正しい:run() 内またはタスクのライフサイクルフック内で呼び出します。
  5. 子タスクが親のキューまたはメタデータを継承すると想定する。

    • 誤り:サブタスクが親の concurrencyLimit を共有したり、親のメタデータを参照できると期待する。
    • 正しい:サブタスクは独自のキューで実行されます。{ metadata: metadata.current() } でメタデータを明示的に渡すか、metadata.parent.* を使って親に反映します。
  6. ネイティブ/WASM パッケージをバンドルする。

    • 誤り:sharp、re2、sqlite3、または WASM パッケージをデフォルトのバンドルに残す。
    • 正しい:trigger.config.ts の build.external に追加します。
  7. 生の文字列の冪等性キーがグローバルだと頼る。

    • 誤り:trigger(p, { idempotencyKey: "welcome-email" }) で一度だけ実行されると期待する(v4.3.0 以前でのみ有効です)。
    • 正しい:await idempotencyKeys.create("welcome-email", { scope: "global" })。

参考資料

関連スキル:

  • trigger-realtime は、実行をサブスクライブし、React フックを使ってフロントエンドからトリガーするためのスキルです。
  • trigger-authoring-chat-agent と trigger-chat-agent-advanced は、AI チャットエージェントを構築するためのスキルです。

参考ドキュメントは同じパッケージ内でこのスキルと一緒に提供され、インストール済みバージョンに固定されています。ネットワーク接続は不要なので、ローカルで読んでください。上記の sources: フロントマターには、このスキルが参照するドキュメントがすべて記載されており、すべて @trigger.dev/sdk/docs/ にあります。次のドキュメントから始めてください。

  • @trigger.dev/sdk/docs/tasks/overview.mdx
  • @trigger.dev/sdk/docs/triggering.mdx
  • @trigger.dev/sdk/docs/config/config-file.mdx

バージョン

このスキルは @trigger.dev/sdk に同梱され、node_modules から直接読み込まれるため、インストール済みの SDK バージョンと常に一致します(隣接する package.json を参照してください)。これらの API に関するドキュメント一式も、@trigger.dev/sdk/docs/ に同梱されています。

コメント