Agent Skills by ALSEL
Anthropic ClaudeLLM・AI開発⭐ リポ 0品質スコア 50/100

workflow-automation

ワークフロー自動化は、AIエージェントを安定稼働させるための基盤インフラです。耐久性のある実行環境がなければ、10ステップの決済フロー中にネットワーク障害が発生した際、損失や顧客クレームに直結しますが、この仕組みがあれば中断した箇所から正確に処理を再開できます。

description の原文を見る

Workflow automation is the infrastructure that makes AI agents reliable. Without durable execution, a network hiccup during a 10-step payment flow means lost money and angry customers. With it, workflows resume exactly where they left off.

SKILL.md 本文

ワークフロー自動化

ワークフロー自動化は、AI エージェントを信頼性の高いものにするインフラストラクチャです。耐久的実行がなければ、10ステップの支払いフロー中のネットワーク障害は資金喪失と顧客満足度低下を意味します。耐久的実行があれば、ワークフローは中断したところから正確に再開できます。

このスキルは、脆弱なスクリプトを本番グレードの自動化に変えるプラットフォーム(n8n、Temporal、Inngest)とパターン(順序実行、並列実行、オーケストレーター・ワーカー)をカバーしています。

重要な洞察:プラットフォームは異なるトレードオフを行います。n8n はアクセシビリティに最適化され、Temporal は正確性に、Inngest は開発者体験に最適化されています。ハイプではなく、実際のニーズに基づいて選択してください。

原則

  • 耐久的実行は金銭または状態が重要なワークフローでは必須です
  • イベントはワークフロー トリガーの普遍的な言語です
  • ステップはチェックポイント - 各ステップは独立して再試行可能である必要があります
  • シンプルな状態から始めて、信頼性が必要な場合にのみ複雑さを追加します
  • 監視可能性はオプションではありません - ワークフローがどこで失敗するかを確認する必要があります
  • ワークフローとエージェントは共進化します - 両方に対して設計してください

機能

  • workflow-automation
  • workflow-orchestration
  • durable-execution
  • event-driven-workflows
  • step-functions
  • job-queues
  • background-jobs
  • scheduled-tasks

スコープ

  • multi-agent-coordination → multi-agent-orchestration
  • ci-cd-pipelines → devops
  • data-pipelines → data-engineer
  • api-design → api-designer

ツーリング

プラットフォーム

  • n8n - 使用時機:ローコード自動化、迅速なプロトタイピング、非技術系ユーザー 注記:自己ホスト可能、400以上の統合、ビジュアルワークフローに最適
  • Temporal - 使用時機:ミッションクリティカルなワークフロー、金融取引、マイクロサービス 注記:最強の耐久性保証、急な学習曲線
  • Inngest - 使用時機:イベント駆動型サーバーレス、TypeScript コードベース、AI ワークフロー 注記:最高の開発者体験、あらゆるホスティングで動作
  • AWS Step Functions - 使用時機:AWS ネイティブスタック、既存の Lambda 関数 注記:タイトな AWS 統合、JSON ベースのワークフロー定義
  • Azure Durable Functions - 使用時機:Azure スタック、.NET または TypeScript 注記:AI エージェント対応、チェックポイントと再生

パターン

順序実行パターン

ステップは順序で実行され、各出力は次の入力になります

使用時機:コンテンツパイプライン、データ処理、順序付き操作

ステップ 1 → ステップ 2 → ステップ 3 → 出力
  ↓         ↓         ↓
(各ステップでチェックポイント)

Inngest の例(TypeScript)

import { inngest } from "./client";

export const processOrder = inngest.createFunction(
  { id: "process-order" },
  { event: "order/created" },
  async ({ event, step }) => {
    // ステップ 1: 注文を検証
    const validated = await step.run("validate-order", async () => {
      return validateOrder(event.data.order);
    });

    // ステップ 2: 支払いを処理(耐久的 - クラッシュから復帰)
    const payment = await step.run("process-payment", async () => {
      return chargeCard(validated.paymentMethod, validated.total);
    });

    // ステップ 3: 配送を作成
    const shipment = await step.run("create-shipment", async () => {
      return createShipment(validated.items, validated.address);
    });

    // ステップ 4: 確認メールを送信
    await step.run("send-confirmation", async () => {
      return sendEmail(validated.email, { payment, shipment });
    });

    return { success: true, orderId: event.data.orderId };
  }
);

Temporal の例(TypeScript)

import { proxyActivities } from '@temporalio/workflow';
import type * as activities from './activities';

const { validateOrder, chargeCard, createShipment, sendEmail } =
  proxyActivities<typeof activities>({
    startToCloseTimeout: '30 seconds',
    retry: {
      maximumAttempts: 3,
      backoffCoefficient: 2,
    }
  });

export async function processOrderWorkflow(order: Order): Promise<void> {
  const validated = await validateOrder(order);
  const payment = await chargeCard(validated.paymentMethod, validated.total);
  const shipment = await createShipment(validated.items, validated.address);
  await sendEmail(validated.email, { payment, shipment });
}

n8n パターン

[Webhook: order.created]
    ↓
[HTTP リクエスト: 注文を検証]
    ↓
[HTTP リクエスト: 支払いを処理]
    ↓
[HTTP リクエスト: 配送を作成]
    ↓
[メール送信: 確認]

各ノードをフェイル時の再試行で設定します。
エラーハンドリングには Error Trigger を使用します。

並列実行パターン

独立したステップが同時に実行され、結果を集約

使用時機:複数の独立した分析、複数のソースからのデータ

        ┌→ ステップ A ─┐
入力 ──┼→ ステップ B ─┼→ 集約 → 出力
        └→ ステップ C ─┘

Inngest の例

export const analyzeDocument = inngest.createFunction(
  { id: "analyze-document" },
  { event: "document/uploaded" },
  async ({ event, step }) => {
    // 分析を並列実行
    const [security, performance, compliance] = await Promise.all([
      step.run("security-analysis", () =>
        analyzeForSecurityIssues(event.data.document)
      ),
      step.run("performance-analysis", () =>
        analyzeForPerformance(event.data.document)
      ),
      step.run("compliance-analysis", () =>
        analyzeForCompliance(event.data.document)
      ),
    ]);

    // 結果を集約
    const report = await step.run("generate-report", () =>
      generateReport({ security, performance, compliance })
    );

    return report;
  }
);

AWS Step Functions(Amazon States Language)

{
  "Type": "Parallel",
  "Branches": [
    {
      "StartAt": "SecurityAnalysis",
      "States": {
        "SecurityAnalysis": {
          "Type": "Task",
          "Resource": "arn:aws:lambda:...:security-analyzer",
          "End": true
        }
      }
    },
    {
      "StartAt": "PerformanceAnalysis",
      "States": {
        "PerformanceAnalysis": {
          "Type": "Task",
          "Resource": "arn:aws:lambda:...:performance-analyzer",
          "End": true
        }
      }
    }
  ],
  "Next": "AggregateResults"
}

オーケストレーター・ワーカーパターン

中央コーディネーターが専門化されたワーカーに作業をディスパッチ

使用時機:異なる専門知識が必要な複雑なタスク、動的サブタスク作成

┌─────────────────────────────────────┐
│         オーケストレーター           │
│  - タスクを分析                      │
│  - サブタスクを作成                  │
│  - ワーカーにディスパッチ            │
│  - 結果を集約                        │
└─────────────────────────────────────┘
                │
    ┌───────────┼───────────┐
    ▼           ▼           ▼
┌───────┐  ┌───────┐  ┌───────┐
│ワーカー1│ │ワーカー2│ │ワーカー3│
│作成    │  │修正    │  │削除    │
└───────┘  └───────┘  └───────┘

Temporal の例

export async function orchestratorWorkflow(task: ComplexTask) {
  // オーケストレーターが実行する必要のある作業を決定
  const plan = await analyzeTask(task);

  // 専門化されたワーカーワークフローにディスパッチ
  const results = await Promise.all(
    plan.subtasks.map(subtask => {
      switch (subtask.type) {
        case 'create':
          return executeChild(createWorkerWorkflow, { args: [subtask] });
        case 'modify':
          return executeChild(modifyWorkerWorkflow, { args: [subtask] });
        case 'delete':
          return executeChild(deleteWorkerWorkflow, { args: [subtask] });
      }
    })
  );

  // 結果を集約
  return aggregateResults(results);
}

AI オーケストレーション付き Inngest

export const aiOrchestrator = inngest.createFunction(
  { id: "ai-orchestrator" },
  { event: "task/complex" },
  async ({ event, step }) => {
    // AI が何をする必要があるかを決定
    const plan = await step.run("create-plan", async () => {
      return await llm.chat({
        messages: [
          { role: "system", content: "このタスクをサブタスクに分割..." },
          { role: "user", content: event.data.task }
        ]
      });
    });

    // 各サブタスクを耐久的ステップとして実行
    const results = [];
    for (const subtask of plan.subtasks) {
      const result = await step.run(`execute-${subtask.id}`, async () => {
        return executeSubtask(subtask);
      });
      results.push(result);
    }

    // 最終的な統合
    return await step.run("synthesize", async () => {
      return synthesizeResults(results);
    });
  }
);

イベント駆動型トリガーパターン

スケジュールではなくイベントで駆動されるワークフロー

使用時機:リアクティブシステム、ユーザーアクション、Webhook 統合

イベント駆動型トリガー

Inngest イベントベース

// TypeScript 型を使用してイベントを定義
type Events = {
  "user/signed.up": {
    data: { userId: string; email: string };
  };
  "order/completed": {
    data: { orderId: string; total: number };
  };
};

// このイベントで駆動される関数
export const onboardUser = inngest.createFunction(
  { id: "onboard-user" },
  { event: "user/signed.up" },  // このイベントで駆動
  async ({ event, step }) => {
    // 1 時間待機してからウェルカムメールを送信
    await step.sleep("wait-for-exploration", "1 hour");

    await step.run("send-welcome", async () => {
      return sendWelcomeEmail(event.data.email);
    });

    // 3 日間待機してエンゲージメントを確認
    await step.sleep("wait-for-engagement", "3 days");

    const engaged = await step.run("check-engagement", async () => {
      return checkUserEngagement(event.data.userId);
    });

    if (!engaged) {
      await step.run("send-nudge", async () => {
        return sendNudgeEmail(event.data.email);
      });
    }
  }
);

// どこからでもイベントを送信
await inngest.send({
  name: "user/signed.up",
  data: { userId: "123", email: "user@example.com" }
});

n8n Webhook トリガー

[Webhook: POST /api/webhooks/order]
    ↓
[スイッチ: event.type]
    ↓ order.created
[新規注文処理サブワークフロー]
    ↓ order.cancelled
[キャンセル処理サブワークフロー]

再試行と復帰パターン

バックオフ付き自動再試行、デッドレター処理

使用時機:外部依存を持つあらゆるワークフロー

再試行と復帰

Temporal 再試行設定

const activities = proxyActivities<typeof activitiesType>({
  startToCloseTimeout: '30 seconds',
  retry: {
    initialInterval: '1 second',
    backoffCoefficient: 2,
    maximumInterval: '1 minute',
    maximumAttempts: 5,
    nonRetryableErrorTypes: [
      'ValidationError',      // 検証失敗は再試行しない
      'InsufficientFunds',    // 支払い失敗は再試行しない
    ]
  }
});

Inngest 再試行設定

export const processPayment = inngest.createFunction(
  {
    id: "process-payment",
    retries: 5,  // 最大 5 回再試行
  },
  { event: "payment/initiated" },
  async ({ event, step, attempt }) => {
    // attempt は 0 インデックスの再試行カウント

    const result = await step.run("charge-card", async () => {
      try {
        return await stripe.charges.create({...});
      } catch (error) {
        if (error.code === 'card_declined') {
          // カード拒否は再試行しない
          throw new NonRetriableError("Card declined");
        }
        throw error;  // その他のエラーは再試行
      }
    });

    return result;
  }
);

デッドレターハンドリング

// n8n: Error Trigger ノードを使用
[Error Trigger]
    ↓
[エラーデータベースにログ]
    ↓
[Slack にアラートを送信]
    ↓
[Jira でチケットを作成]

// Inngest: onFailure でハンドル
export const myFunction = inngest.createFunction(
  {
    id: "my-function",
    onFailure: async ({ error, event, step }) => {
      await step.run("alert-team", async () => {
        await slack.postMessage({
          channel: "#errors",
          text: `Function failed: ${error.message}`
        });
      });
    }
  },
  { event: "..." },
  async ({ step }) => { ... }
);

スケジュール実行パターン

定期的なタスク用の時間ベースのトリガー

使用時機:日報、定期同期、バッチ処理

スケジュール実行

Inngest Cron

export const dailyReport = inngest.createFunction(
  { id: "daily-report" },
  { cron: "0 9 * * *" },  // 毎日午前 9 時
  async ({ step }) => {
    const data = await step.run("gather-metrics", async () => {
      return gatherDailyMetrics();
    });

    await step.run("generate-report", async () => {
      return generateAndSendReport(data);
    });
  }
);

export const syncInventory = inngest.createFunction(
  { id: "sync-inventory" },
  { cron: "*/15 * * * *" },  // 15 分ごと
  async ({ step }) => {
    await step.run("sync", async () => {
      return syncWithSupplier();
    });
  }
);

Temporal Cron ワークフロー

// ワークフローを Cron スケジュールで実行
const handle = await client.workflow.start(dailyReportWorkflow, {
  taskQueue: 'reports',
  workflowId: 'daily-report',
  cronSchedule: '0 9 * * *',  // 毎日午前 9 時
});

n8n スケジュール トリガー

[スケジュール トリガー: 毎日午前 9:00]
    ↓
[HTTP リクエスト: メトリクスを取得]
    ↓
[コード ノード: レポートを生成]
    ↓
[メール送信: レポート]

鋭い落とし穴

耐久性ワークフロー内の冪等性がないステップ

重大度:CRITICAL

状況:外部状態を修正するワークフローステップを記述

症状: 顧客が 2 回請求される。メールが 3 回送信される。データベースレコードが複数回作成される。ワークフロー再試行は副作用の重複を引き起こします。

これが失敗する理由: 耐久的実行は再開時にワークフローを最初から再生します。ステップ 3 がクラッシュしてワークフローが再開すると、ステップ 1 と 2 が再び実行されます。冪等性キーがないと、外部サービスはこれらが再試行であることを知りません。

推奨修正:

常に外部呼び出しに冪等性キーを使用します:

### Stripe の例:
await stripe.paymentIntents.create({
  amount: 1000,
  currency: 'usd',
  idempotency_key: `order-${orderId}-payment`  # 重要!
});

### メールの例:
await step.run("send-confirmation", async () => {
  const alreadySent = await checkEmailSent(orderId);
  if (alreadySent) return { skipped: true };
  return sendEmail(customer, orderId);
});

### データベースの例:
await db.query(`
  INSERT INTO orders (id, ...) VALUES ($1, ...)
  ON CONFLICT (id) DO NOTHING
`, [orderId]);

冪等性キーを安定した入力から生成し、ランダム値から生成しないでください

数時間/数日間チェックポイントなしで実行するワークフロー

重大度:HIGH

状況:チェックポイント間隔が長い長時間実行ワークフロー

症状: メモリ消費が増加します。ワーカーがタイムアウトします。クラッシュ後に進捗が失われます。「ワークフローが最大期間を超過」エラーが発生します。

これが失敗する理由: ワークフローはチェックポイントまでメモリに状態を保持します。24 時間実行され、1 時間ごとに 1 ステップ実行するワークフローは、24 時間分の状態を蓄積します。ワーカーはメモリ制限があります。関数は実行時間制限があります。

推奨修正:

チェックポイント付きステップに長時間ワークフローを分割します:

### 間違い - 1 つの長いステップ:
await step.run("process-all", async () => {
  for (const item of thousandItems) {
    await processItem(item);  // 数時間の作業、1 つのチェックポイント
  }
});

### 正しい - 多くの小さいステップ:
for (const item of thousandItems) {
  await step.run(`process-${item.id}`, async () => {
    return processItem(item);  // 各ステップ後にチェックポイント
  });
}

非常に長い待機には sleep を使用します:

await step.sleep("wait-for-trial", "14 days");
// 待機中はリソースを消費しません

長いプロセスには子ワークフローを検討します:

await step.invoke("process-batch", {
  function: batchProcessor,
  data: { items: batch }
});

タイムアウト設定がないアクティビティ

重大度:HIGH

状況:ワークフローアクティビティから外部サービスを呼び出す

症状: ワークフローが無期限にハングします。ワーカープールが枯渇します。完了しない、または失敗しないデッドワークフロー。スタックされたワークフローを強制終了するために手動介入が必要です。

これが失敗する理由: 外部 API は無期限にハングする可能性があります。タイムアウトなしで、ワークフローは無期限に待機します。HTTP クライアントとは異なり、ワークフローアクティビティにはほとんどのプラットフォームでデフォルトのタイムアウトがありません。

推奨修正:

常にアクティビティにタイムアウトを設定します:

### Temporal:
const activities = proxyActivities<typeof activitiesType>({
  startToCloseTimeout: '30 seconds',  # 必須!
  scheduleToCloseTimeout: '5 minutes',
  heartbeatTimeout: '10 seconds',  # 長いアクティビティ用
  retry: {
    maximumAttempts: 3,
    initialInterval: '1 second',
  }
});

### Inngest:
await step.run("call-api", { timeout: "30s" }, async () => {
  return fetch(url, { signal: AbortSignal.timeout(25000) });
});

## AWS Step Functions:
{
  "Type": "Task",
  "TimeoutSeconds": 30,
  "HeartbeatSeconds": 10,
  "Resource": "arn:aws:lambda:..."
}

ルール:アクティビティタイムアウト < ワークフロータイムアウト

ステップ/アクティビティ境界外の副作用

重大度:CRITICAL

状況:ワークフロー再生中に実行されるコードを記述

症状: 再生時のランダムな失敗。「ワークフロー破損」エラー。再生時に最初の実行と異なる動作。非決定論的エラー。

これが失敗する理由: ワークフローコードはすべての再生で実行されます。ワークフローコードでランダム ID を生成すると、再生のたびに異なる ID を取得します。現在の時刻を読むと、異なる時刻を取得します。これは決定論を破ります。

推奨修正:

### 間違い - ワークフローコード内の副作用:
export async function orderWorkflow(order) {
  const orderId = uuid();  // 再生のたびに異なる!
  const now = new Date();  // 再生のたびに異なる!
  await activities.process(orderId, now);
}

### 正しい - アクティビティ内の副作用:
export async function orderWorkflow(order) {
  const orderId = await activities.generateOrderId();  # 記録される
  const now = await activities.getCurrentTime();       # 記録される
  await activities.process(orderId, now);
}

### また正しい - Temporal workflow.now() と sideEffect:
import { sideEffect } from '@temporalio/workflow';

const orderId = await sideEffect(() => uuid());
const now = workflow.now();  # 決定論的な再生安全な時刻

ワークフローコードで安全な副作用:

- 関数引数の読み取り
- シンプルな計算(ランダムなし)
- ロギング(通常)

指数バックオフなしの再試行設定

重大度:MEDIUM

状況:失敗するステップの再試行動作を設定

症状: 失敗するサービスに圧力がかかります。レート制限。カスケード障害。再試行ストームが停止を引き起こします。外部 API によってブロックされます。

これが失敗する理由: サービスが苦しんでいる場合、即座の再試行はそれを悪化させます。100 個のワークフローが即座に再試行 = 既に失敗しているサービスに 100 個のリクエストがヒットします。バックオフはサービスに復帰する時間を与えます。

推奨修正:

常に指数バックオフを使用します:

### Temporal:
const activities = proxyActivities({
  retry: {
    initialInterval: '1 second',
    backoffCoefficient: 2,       # 1s, 2s, 4s, 8s, 16s...
    maximumInterval: '1 minute',  # バックオフをキャップ
    maximumAttempts: 5,
  }
});

### Inngest(組み込みバックオフ):
{
  id: "my-function",
  retries: 5,  # デフォルトで指数バックオフを使用
}

### 手動バックオフ:
const backoff = (attempt) => {
  const base = 1000;
  const max = 60000;
  const delay = Math.min(base * Math.pow(2, attempt), max);
  const jitter = delay * 0.1 * Math.random();
  return delay + jitter;
};

スタンピングの群れを防ぐためにジッターを追加します

ワークフロー状態への大規模データの保存

重大度:HIGH

状況:ワークフローステップ間で大規模なペイロードを渡す

症状: ワークフロー実行が遅くなります。メモリエラー。「ペイロードが大きすぎます」エラー。ストレージコストが高くなります。再生が遅くなります。

これが失敗する理由: ワークフロー状態は永続化され、再生されます。10 MB のペイロードは保存、シリアライズ、すべてのステップで逆シリアライズされます。これはレイテンシーとコストを追加します。一部のプラットフォームにはハードリミットがあります(例:Step Functions 256KB)。

推奨修正:

### 間違い - ワークフロー内の大規模データ:
await step.run("fetch-data", async () => {
  const largeDataset = await fetchAllRecords();  // 100MB!
  return largeDataset;  // ワークフロー状態に保存
});

### 正しい - 参照を保存、データではなく:
await step.run("fetch-data", async () => {
  const largeDataset = await fetchAllRecords();
  const s3Key = await uploadToS3(largeDataset);
  return { s3Key };  // 参照のみ
});

const processed = await step.run("process-data", async () => {
  const data = await downloadFromS3(fetchResult.s3Key);
  return processData(data);
});

Step Functions の場合、大規模ペイロードに S3 を使用します:

{
  "Type": "Task",
  "Resource": "arn:aws:states:::s3:putObject",
  "Parameters": {
    "Bucket": "my-bucket",
    "Key.$": "$.outputKey",
    "Body.$": "$.largeData"
  }
}

デッドレターキューまたはフェイルハンドラーがない

重大度:HIGH

状況:すべての再試行を使い果たすワークフロー

症状: 失敗したワークフローが静かに消える。問題が発生しても、アラートなし。顧客の問題が数日後に発見されます。手動復帰が不可能です。

これが失敗する理由: 再試行でも、一部のワークフローは永続的に失敗します。デッドレターハンドリングがなければ、失敗を知りません。顧客は無期限に待機し、あなたは気付かず、デバッグするデータがありません。

推奨修正:

// Inngest onFailure ハンドラー:
export const myFunction = inngest.createFunction(
  {
    id: "process-order",
    onFailure: async ({ error, event, step }) => {
      // エラー追跡にログ
      await step.run("log-error", () =>
        sentry.captureException(error, { extra: { event } })
      );

      // チームにアラート
      await step.run("alert", () =>
        slack.postMessage({
          channel: "#alerts",
          text: `Order ${event.data.orderId} failed: ${error.message}`
        })
      );

      // 手動レビュー用にキュー
      await step.run("queue-review", () =>
        db.insert(failedOrders, { orderId, error, event })
      );
    }
  },
  { event: "order/created" },
  async ({ event, step }) => { ... }
);

n8n エラーハンドリング:

[Error Trigger]  →  [DB にログ]  →  [Slack アラート]  →  [チケット作成]

Temporal:workflow.failed またはワークフロー信号を使用します

エラートリガーなしの n8n ワークフロー

重大度:MEDIUM

状況:本番環境 n8n ワークフロー構築

症状: ワークフローが静かに失敗します。エラーは실行ログでのみ表示されます。アラートなし、復帰なし、誰かが気付くまで可視性なし。

これが失敗する理由: n8n はデフォルトで失敗時に通知しません。Error Trigger ノードがアラート機能に接続されていないと、失敗は UI にのみ表示されます。本番環境の失敗は気付かれません。

推奨修正:

すべての本番環境 n8n ワークフローには以下が必要です:

  1. Error Trigger ノード

    • ワークフロー内の任意のノード失敗をキャッチ
    • エラーの詳細とコンテキストを提供
  2. 接続されたエラーハンドリング:

    [Error Trigger]
        ↓
    [設定: エラーの詳細を抽出]
        ↓
    [HTTP: エラーサービスにログ]
        ↓
    [Slack/メール: チームにアラート]
    
  3. デッドレターパターンを検討:

    [Error Trigger]
        ↓
    [Redis/Postgres: 失敗したジョブを保存]
        ↓
    [別の復帰ワークフロー]
    

また使用:

- ノード失敗時の再試行(組み込み)
- ノードタイムアウト設定
- ワークフロータイムアウト

ハートビートなしの長実行 Temporal アクティビティ

重大度:MEDIUM

状況:数秒以上実行されるアクティビティ

症状: アクティビティがタイムアウトしても、作業が進行中です。ワーカーが再開時に作業が失われます。長時間実行されるアクティビティをキャンセルできません。

これが失敗する理由: Temporal はハートビート経由でスタックしたアクティビティを検出します。ハートビートなしで、Temporal はアクティビティが動作しているか、スタックしているかを判断できません。長いアクティビティはハングしているように見え、タイムアウトする可能性があり、適切にキャンセルできません。

推奨修正:

// 10 秒以上のアクティビティの場合、ハートビートを追加:

import { heartbeat, activityInfo } from '@temporalio/activity';

export async function processLargeFile(fileUrl: string): Promise<void> {
  const chunks = await downloadChunks(fileUrl);

  for (let i = 0; i < chunks.length; i++) {
    // キャンセルをチェック
    const { cancelled } = activityInfo();
    if (cancelled) {
      throw new CancelledFailure('Activity cancelled');
    }

    await processChunk(chunks[i]);

    // 進捗を報告
    heartbeat({ progress: (i + 1) / chunks.length });
  }
}

// ハートビートタイムアウトを設定:
const activities = proxyActivities({
  startToCloseTimeout: '10 minutes',
  heartbeatTimeout: '30 seconds',  # 30 秒ごとにハートビート必須
});

30 秒間ハートビートなしで、アクティビティはスタックと見なされます

検証チェック

冪等性キーなしの外部呼び出し

重大度:ERROR

Stripe/支払い呼び出しは冪等性キーを使用すべき

メッセージ:idempotency_key なしの支払い呼び出し。再試行時の重複請求を防ぐために冪等性キーを追加します。

重複排除なしのメール送信

重大度:WARNING

ワークフロー内のメール送信は既送を確認すべき

メッセージ:重複排除チェックなしでワークフロー内でメール送信。再試行が重複メールを送信する可能性があります。

タイムアウトなし Temporal アクティビティ

重大度:ERROR

すべての Temporal アクティビティにはタイムアウト設定が必要

メッセージ:タイムアウトなしの proxyActivities。無期限のハングを防ぐために startToCloseTimeout を追加します。

タイムアウトなしで外部 API を呼び出す Inngest ステップ

重大度:WARNING

外部 API 呼び出しはタイムアウトを持つべき

メッセージ:タイムアウトなしのステップ内での外部 API 呼び出し。ワークフローハングを防ぐためにタイムアウトを追加します。

ワークフローコード内のランダム値

重大度:ERROR

ランダム値は再生時に決定論を破ります

メッセージ:ワークフローコード内のランダム値。アクティビティ/ステップに移動するか、sideEffect を使用します。

ワークフローコード内の Date.now()

重大度:ERROR

現在時刻は再生時に決定論を破ります

メッセージ:ワークフローコード内の現在時刻。workflow.now() を使用するか、アクティビティ/ステップに移動します。

onFailure ハンドラーなし Inngest 関数

重大度:WARNING

本番環境の関数はフェイルハンドラーを持つべき

メッセージ:onFailure ハンドラーなしの Inngest 関数。本番環境の信頼性のためにフェイルハンドリングを追加します。

エラーハンドリングなしのステップ

重大度:WARNING

ステップはエラーを適切にハンドルすべき

メッセージ:try/catch なしのステップ。特定のエラーケースのハンドリングを検討します。

ステップから返される可能性のある大規模データ

重大度:INFO

ワークフロー状態内の大規模データは実行を遅くします

メッセージ:ステップから可能性のある大規模データを返却。S3/DB に保存して参照を返すことを検討します。

バックオフ設定なしの再試行

重大度:WARNING

再試行は指数バックオフを使用すべき

メッセージ:バックオフなしで設定された再試行。backoffCoefficient と initialInterval を追加します。

コラボレーション

委譲トリガー

  • ユーザーがマルチエージェント調整が必要 -> multi-agent-orchestration(ワークフローはインフラを提供し、オーケストレーションはパターンを提供)
  • ユーザーがワークフロー用のツール構築が必要 -> agent-tool-builder(ワークフローが呼び出せるツール)
  • ユーザーが Zapier/Make 統合が必要 -> zapier-make-patterns(ノーコード自動化プラットフォーム)
  • ユーザーがワークフロー内のブラウザ自動化が必要 -> browser-automation(Playwright/Puppeteer アクティビティ)
  • ユーザーがワークフロー内のコンピューター制御が必要 -> computer-use-agents(デスクトップ自動化アクティビティ)
  • ユーザーがワークフロー内の LLM 統合が必要 -> llm-architect(AI 駆動ワークフローステップ)

関連スキル

相性の良いスキル:multi-agent-orchestrationagent-tool-builderbackenddevops

使用時機

  • ユーザーが workflow について言及または暗示
  • ユーザーが automation について言及または暗示
  • ユーザーが n8n について言及または暗示
  • ユーザーが temporal について言及または暗示
  • ユーザーが inngest について言及または暗示
  • ユーザーが step function について言及または暗示
  • ユーザーが background job について言及または暗示
  • ユーザーが durable execution について言及または暗示
  • ユーザーが event-driven について言及または暗示
  • ユーザーが scheduled task について言及または暗示
  • ユーザーが job queue について言及または暗示
  • ユーザーが cron について言及または暗示
  • ユーザーが trigger について言及または暗示

制限事項

  • このスキルは上記のスコープで説明されたタスクに明確に一致する場合にのみ使用します。
  • 出力を環境固有の検証、テスト、または専門家レビューの代替として扱わないでください。
  • 必要な入力、権限、安全性の境界、または成功基準が不足している場合は、停止して明確化を求めてください。

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
sickn33
リポジトリ
sickn33/antigravity-awesome-skills
ライセンス
MIT
最終更新
不明

Source: https://github.com/sickn33/antigravity-awesome-skills / ライセンス: MIT

関連スキル

OpenAILLM・AI開発⭐ リポ 6,054

agent-browser

AI エージェント向けのブラウザ自動化 CLI です。ウェブサイトとの対話が必要な場合に使用します。ページ遷移、フォーム入力、ボタンクリック、スクリーンショット取得、データ抽出、ウェブアプリのテスト、ブラウザ操作の自動化など、あらゆるブラウザタスクに対応できます。「ウェブサイトを開く」「フォームに記入する」「ボタンをクリックする」「スクリーンショットを取得する」「ページからデータを抽出する」「このウェブアプリをテストする」「サイトにログインする」「ブラウザ操作を自動化する」といった要求や、プログラマティックなウェブ操作が必要なタスクで起動します。

by JimmyLv
汎用LLM・AI開発⭐ リポ 1,982

anyskill

AnySkill — あなたのプライベート・スキルクラウド。GitHubを基盤としたリポジトリからエージェントスキルを管理、同期、動的にロードできます。自然言語でクラウドスキルを検索し、オンデマンドでプロンプトを自動ロード、カスタムスキルのアップロードと共有、スキルバンドルの一括インストールが可能です。OpenClaw、Antigravity、Claude Code、Cursorに対応しています。

by LeoYeAI
汎用LLM・AI開発⭐ リポ 1,982

engram

AIエージェント向けの永続的なメモリシステムです。バグ修正、意思決定、発見、設定変更の後はmem_saveを使用してください。ユーザーが「覚えている」「記憶している」と言及した場合、または以前のセッションと重複する作業を開始する際はmem_searchを使用します。セッション終了前にmem_session_summaryを使用して、コンテキストを保持してください。

by LeoYeAI
汎用LLM・AI開発⭐ リポ 21,584

skyvern

AI駆動のブラウザ自動化により、任意のウェブサイトを自動化できます。フォーム入力、データ抽出、ファイルダウンロード、ログイン、複数ステップのワークフロー実行など、ユーザーがウェブサイトと連携する必要があるときに使用します。Skyvernは、LLMとコンピュータビジョンを活用して、未知のサイトも自動操作可能です。Python SDK、TypeScript SDK、REST API、MCPサーバー、またはCLIを通じて統合できます。

by Skyvern-AI
汎用LLM・AI開発⭐ リポ 1,149

pinchbench

PinchBenchベンチマークを実行して、OpenClawエージェントの実世界タスクにおけるパフォーマンスを評価できます。モデルの機能テスト、モデル間の比較、ベンチマーク結果のリーダーボード提出、またはOpenClawのセットアップがカレンダー、メール、リサーチ、コーディング、複数ステップのワークフローにどの程度対応しているかを確認する際に使用します。

by pinchbench
汎用LLM・AI開発⭐ リポ 4,693

openui

OpenUIとOpenUI Langを使用してジェネレーティブUIアプリを構築できます。これらはLLM生成インターフェースのためのトークン効率的なオープン標準です。OpenUI、@openuidev、ジェネレーティブUI、LLMからのストリーミングUI、AI向けコンポーネントライブラリ、またはjson-render/A2UIの置き換えについて述べる際に使用します。スキャフォルディング、defineComponent、システムプロンプト、Renderer、およびOpenUI Lang出力のデバッグに対応しています。

by thesysdev
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: sickn33 · sickn33/antigravity-awesome-skills · ライセンス: MIT