inngest-handler
信頼性の高いバックグラウンド処理、ワークフロー、スケジュールされたタスクのために、Inngest関数を作成・管理し、ビジネスにおける様々な処理を効率化・自動化するSkill。
📜 元の英語説明(参考)
Create and manage Inngest functions for reliable background jobs, workflows, and scheduled tasks.
🇯🇵 日本人クリエイター向け解説
信頼性の高いバックグラウンド処理、ワークフロー、スケジュールされたタスクのために、Inngest関数を作成・管理し、ビジネスにおける様々な処理を効率化・自動化するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o inngest-handler.zip https://jpskill.com/download/16909.zip && unzip -o inngest-handler.zip && rm inngest-handler.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/16909.zip -OutFile "$d\inngest-handler.zip"; Expand-Archive "$d\inngest-handler.zip" -DestinationPath $d -Force; ri "$d\inngest-handler.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
inngest-handler.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
inngest-handlerフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Inngest Function Handler Skill
この Skill は、Inngest を使用して耐久性のある、複数ステップのワークフローを構築するための標準を定義します。
🚨 厳守事項 (厳密に従ってください)
-
setTimeout/setIntervalを使用しない:- ❌ 悪い例:
await new Promise(r => setTimeout(r, 1000)) - ✅ 良い例:
await step.sleep("wait-1s", "1s") - 理由: サーバーレス関数はタイムアウトします。Inngest のスリープは最大 1 年間持続します。
- ❌ 悪い例:
-
ステップ外で副作用を起こさない:
- データベースへの書き込み、API 呼び出し、または非決定的なロジック (ランダム、日付) は、必ず
step.run()でラップする必要があります。 - 理由: Inngest 関数は複数回実行されます (メモ化)。ステップ外のコードは毎回実行されます。
- データベースへの書き込み、API 呼び出し、または非決定的なロジック (ランダム、日付) は、必ず
-
決定的なステップ:
- ステップは ID (最初の引数) によってメモ化されます。ID は一意で安定している必要があります。
- ステップ ID を動的に生成しないでください (インデックス付きのループ内など、特別な理由がない限り)。
-
ステップからデータを返す:
- 後で値が必要な場合は、ステップから返します。
- ❌ 悪い例:
let userId; await step.run(..., () => { userId = ... }) - ✅ 良い例:
const userId = await step.run(..., () => { return ... })
コアパターン
1. 複数ステップの実行
すべてのロジックをステップでラップして、再試行可能性と再開可能性を確保します。
export const processOrder = inngest.createFunction(
{ id: "process-order" },
{ event: "shop/order.created" },
async ({ event, step }) => {
// 1. Step: Validate (再試行可能)
const user = await step.run("get-user", async () => {
return await db.users.findById(event.data.userId);
});
// 2. Step: Sleep (耐久性のある一時停止)
await step.sleep("wait-for-payment", "1h");
// 3. Step: Wait for Event (人間/システムとのインタラクション)
const payment = await step.waitForEvent("wait-payment", {
event: "shop/payment.success",
match: "data.orderId",
timeout: "24h"
});
// 4. Step: 条件付きロジック
if (!payment) {
await step.run("cancel-order", async () => { ... });
}
}
);
2. 並列処理
ステップを同時に実行して、実行を高速化します。
const [user, subscription] = await Promise.all([
step.run("fetch-user", () => db.users.find(...)),
step.run("fetch-sub", () => stripe.subscriptions.retrieve(...))
]);
3. ループの処理
ループ内では、ステップ ID が一意であることを確認します。
const items = event.data.items;
for (const item of items) {
// アイテムごとに一意性を確保するために動的な ID を使用します
await step.run(`process-item-${item.id}`, async () => {
await processItem(item);
});
}
構成とフロー制御
レート制限とスロットリング
サードパーティ API への過負荷を防ぎます。
inngest.createFunction({
id: "sync-crm",
// ユーザーあたり 1 分あたり最大 10 リクエスト
rateLimit: { limit: 10, period: "1m", key: "event.data.userId" },
// キューがいっぱいの場合はイベントをドロップします
throttle: { limit: 5, period: "1s" }
}, ...);
デバウンス
ウィンドウ内の最新のイベントのみを処理します (例: 検索インデックス作成)。
inngest.createFunction({
id: "index-product",
// より多くのイベントを 10 秒間待ちます。最新のデータでのみ実行します
debounce: { period: "10s", key: "event.data.productId" }
}, ...);
優先度
特定のイベントを優先します (例: 有料ユーザー)。
inngest.createFunction({
id: "generate-report",
// 数値が高いほど優先度が高くなります
priority: { run: "event.data.plan === 'enterprise' ? 100 : 0" }
}, ...);
エラー処理
自動再試行
Inngest は、エラーが発生した場合にステップを自動的に再試行します (デフォルトではバックオフありで約 4 ~ 5 回)。
- カスタマイズ: config で
{ retries: 10 }。
再試行不可能なエラー
エラーが致命的な場合 (例: 400 Bad Request) は、すぐに実行を停止します。
import { NonRetriableError } from "inngest";
await step.run("validate", async () => {
if (!isValid) throw new NonRetriableError("Invalid payload");
});
失敗ハンドラー (ロールバック)
すべての再試行後に関数が失敗した場合に、クリーンアップロジックを実行します。
export const riskyFunc = inngest.createFunction(
{
id: "risky-transfer",
// メインハンドラーが失敗した場合に実行されます
onFailure: async ({ error, event, step }) => {
await step.run("rollback-funds", async () => {
await reverseTransfer(event.data.transferId);
});
await step.run("notify-admin", async () => {
await sendAlert(`Transfer failed: ${error.message}`);
});
}
},
{ event: "bank/transfer.init" },
async ({ step }) => { /* ... */ }
);
登録
必須: すべての関数は src/lib/inngest/functions/index.ts でインポートおよびエクスポートする必要があります。
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Inngest Function Handler Skill
This skill defines the standards for building durable, multi-step workflows using Inngest.
🚨 HARD RULES (Strictly Follow)
-
NO
setTimeout/setInterval:- ❌ Bad:
await new Promise(r => setTimeout(r, 1000)) - ✅ Good:
await step.sleep("wait-1s", "1s") - Reason: Serverless functions time out; Inngest sleeps persist for up to a year.
- ❌ Bad:
-
NO Side Effects Outside Steps:
- Any database write, API call, or non-deterministic logic (random, date) MUST be wrapped in
step.run(). - Reason: Inngest functions execute multiple times (memoization). Code outside steps runs every time.
- Any database write, API call, or non-deterministic logic (random, date) MUST be wrapped in
-
Deterministic Steps:
- Steps are memoized by their ID (1st arg). IDs must be unique and stable.
- Do not dynamically generate step IDs unless you know what you are doing (e.g., inside loops with index).
-
Return Data from Steps:
- If you need a value later, return it from the step.
- ❌ Bad:
let userId; await step.run(..., () => { userId = ... }) - ✅ Good:
const userId = await step.run(..., () => { return ... })
Core Patterns
1. Multi-Step Execution
Wrap all logic in steps to ensure retriability and resumability.
export const processOrder = inngest.createFunction(
{ id: "process-order" },
{ event: "shop/order.created" },
async ({ event, step }) => {
// 1. Step: Validate (Retriable)
const user = await step.run("get-user", async () => {
return await db.users.findById(event.data.userId);
});
// 2. Step: Sleep (Durable pause)
await step.sleep("wait-for-payment", "1h");
// 3. Step: Wait for Event (Human/System interaction)
const payment = await step.waitForEvent("wait-payment", {
event: "shop/payment.success",
match: "data.orderId",
timeout: "24h"
});
// 4. Step: Conditional Logic
if (!payment) {
await step.run("cancel-order", async () => { ... });
}
}
);
2. Parallelism
Run steps concurrently to speed up execution.
const [user, subscription] = await Promise.all([
step.run("fetch-user", () => db.users.find(...)),
step.run("fetch-sub", () => stripe.subscriptions.retrieve(...))
]);
3. Working with Loops
Inside loops, ensure step IDs are unique.
const items = event.data.items;
for (const item of items) {
// Use dynamic ID to ensure uniqueness per item
await step.run(`process-item-${item.id}`, async () => {
await processItem(item);
});
}
Configuration & Flow Control
Rate Limiting & Throttling
Prevent overwhelming 3rd party APIs.
inngest.createFunction({
id: "sync-crm",
// Max 10 requests per minute per user
rateLimit: { limit: 10, period: "1m", key: "event.data.userId" },
// Drop events if queue is full
throttle: { limit: 5, period: "1s" }
}, ...);
Debounce
Process only the latest event in a window (e.g., search indexing).
inngest.createFunction({
id: "index-product",
// Wait 10s for more events; only run with the latest data
debounce: { period: "10s", key: "event.data.productId" }
}, ...);
Priority
Prioritize specific events (e.g., Paid users).
inngest.createFunction({
id: "generate-report",
// High number = High priority
priority: { run: "event.data.plan === 'enterprise' ? 100 : 0" }
}, ...);
Error Handling
Automatic Retries
Inngest retries steps automatically on error (default ~4-5 times with backoff).
- Customize:
{ retries: 10 }in config.
Non-Retriable Errors
Stop execution immediately if the error is fatal (e.g., 400 Bad Request).
import { NonRetriableError } from "inngest";
await step.run("validate", async () => {
if (!isValid) throw new NonRetriableError("Invalid payload");
});
Failure Handlers (Rollbacks)
Execute cleanup logic if the function fails after all retries.
export const riskyFunc = inngest.createFunction(
{
id: "risky-transfer",
// Runs if main handler fails
onFailure: async ({ error, event, step }) => {
await step.run("rollback-funds", async () => {
await reverseTransfer(event.data.transferId);
});
await step.run("notify-admin", async () => {
await sendAlert(`Transfer failed: ${error.message}`);
});
}
},
{ event: "bank/transfer.init" },
async ({ step }) => { /* ... */ }
);
Registration
MANDATORY: All functions must be imported and exported in src/lib/inngest/functions/index.ts.