inngest-middleware について
TypeScript 向けの Inngest ミドルウェア活用スキルです。ライフサイクルフック、依存性注入、暗号化、Sentry によるエラー追跡を扱います。
主な機能
- 01ライフサイクルフックの追加
- 02共有依存関係の注入
- 03ステップとイベントデータの暗号化
- 04Sentry によるエラー追跡
- 05ミドルウェア動作のテスト
活用シーン
- 01関数へのログやメトリクス追加
- 02関数間でのクライアント共有
- 03関数データの暗号化
- 04例外とトレースの記録
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ inngest/ inngest-skills --skill inngest-middlewareインストール後、Claude Code で/inngest-middlewareを入力して読み込まれたか確認します。
同梱ファイルreferences/built-in-middleware.mdreferences/dependency-injection.md
詳細
Inngest ミドルウェア
ロギング、エラートラッキング、依存性注入、データ変換といった横断的な関心事を処理するための Inngest ミドルウェアをマスターしましょう。ミドルウェアは関数ライフサイクルの重要なポイントで実行され、可観測性と共有機能のための強力なパターンを可能にします。
これらのスキルは TypeScript に焦点を当てています。 Python または Go については、言語固有のガイダンスとして Inngest ドキュメントを参照してください。コアコンセプトはすべての言語に適用されます。
Note: ミドルウェアシステムは v4 で大幅に書き直されました。ここに記載されているライフサイクルフックは v4 API を反映しています。v3 から移行する場合は、破壊的変更の詳細について移行ガイドを参照してください。
⚠ Realtime を使用する場合は、このスキルではなく
inngest-realtimeスキルを使用してください。 Inngest v3 では、@inngest/realtimeのrealtimeMiddleware()を使用して関数ハンドラーにpublish引数を注入していました。v4 では Realtime がネイティブに搭載されています —step.realtime.publishは組み込みであり、ミドルウェアは不要です。v4 プロジェクトに@inngest/realtimeをインストールしないでください(v3 時代のパッケージであり、実行時にTypeError: Cls is not a constructorを引き起こします)。v4 のパターンについてはinngest-realtimeスキルを参照してください。
ミドルウェアとは?
ミドルウェアを使用すると、Inngest クライアントのライフサイクルのさまざまなポイント(関数の実行中、イベントの送信中など)でコードを実行できます。ミドルウェアは Inngest 実行パイプラインへのフックと考えてください。
ミドルウェアを使用する場面:
- 可観測性: ロギング、トレーシング、メトリクスを追加する
- 依存性注入: クライアントインスタンスを関数間で共有する
- データ変換: データの暗号化/復号、検証、またはエンリッチ
- エラー処理: カスタムのエラートラッキングとアラート
- 認証: ユーザーコンテキストや権限を検証する
ミドルウェアのライフサイクル
ミドルウェアはクライアントレベル(すべての関数に影響)または関数レベル(特定の関数に影響)で登録できます。
実行順序
const inngest = new Inngest({
id: "my-app",
middleware: [
loggingMiddleware, // Runs 1st
errorMiddleware // Runs 2nd
]
});
inngest.createFunction(
{
id: "example",
middleware: [
authMiddleware, // Runs 3rd
metricsMiddleware // Runs 4th
],
triggers: [{ event: "test" }]
},
async () => {
/* function code */
}
);
順序が重要です: クライアントミドルウェアが最初に実行され、次に関数ミドルウェアが指定された順序で実行されます。
カスタムミドルウェアの作成
基本的なミドルウェアの構造
import { InngestMiddleware } from "inngest";
const loggingMiddleware = new InngestMiddleware({
name: "Logging Middleware",
init() {
// Setup phase - runs when client initializes
const logger = setupLogger();
return {
// Function execution lifecycle
// Note: `fn` is loosely typed in middleware generics; fn.id works at runtime
onFunctionRun({ ctx, fn }) {
return {
beforeExecution() {
logger.info("Function starting", {
functionId: fn.id,
eventName: ctx.event.name,
runId: ctx.runId
});
},
afterExecution() {
logger.info("Function completed", {
functionId: fn.id,
runId: ctx.runId
});
},
transformOutput({ result }) {
// Log function output
logger.debug("Function output", {
functionId: fn.id,
output: result.data
});
// Return unmodified result
return { result };
}
};
},
// Event sending lifecycle
onSendEvent() {
return {
transformInput({ payloads }) {
logger.info("Sending events", {
count: payloads.length,
events: payloads.map((p) => p.name)
});
// Spread to convert readonly array to mutable array
return { payloads: [...payloads] };
}
};
}
};
}
});
Python 実装
Python ミドルウェアも同様のパターンに従います。完全な Python の例については、依存性注入リファレンスを参照してください。
## Dependency Injection
Share expensive or stateful clients across all functions. **See [Dependency Injection Reference](./references/dependency-injection.md) for detailed patterns.**
### Quick Example - Built-in DI
```typescript
import { dependencyInjectionMiddleware } from "inngest";
const inngest = new Inngest({
id: 'my-app',
middleware: [
dependencyInjectionMiddleware({
openai: new OpenAI(),
db: new PrismaClient(),
}),
],
});
// Functions automatically get injected dependencies
inngest.createFunction(
{ id: "ai-summary", triggers: [{ event: "document/uploaded" }] },
async ({ event, openai, db }) => {
// Dependencies available in function context
const summary = await openai.chat.completions.create({
messages: [{ role: "user", content: event.data.content }],
model: "gpt-4",
});
await db.document.update({
where: { id: event.data.documentId },
data: { summary: summary.choices[0].message.content }
});
}
);
ミドルウェアパッケージ
dependencyInjectionMiddleware(組み込み、上記で表示)以外にも、Inngest は公式ミドルウェアを別個のパッケージとして提供しています。完全な詳細については、ミドルウェアリファレンスを参照してください。
暗号化ミドルウェア
npm install @inngest/middleware-encryption
import { encryptionMiddleware } from "@inngest/middleware-encryption";
const inngest = new Inngest({
id: "my-app",
middleware: [
encryptionMiddleware({
key: process.env.ENCRYPTION_KEY
})
]
});
すべてのステップデータ、関数の出力、およびイベントの data.encrypted フィールドを自動的に暗号化します。fallbackDecryptionKeys によるキーローテーションをサポートします。
Sentry エラートラッキング
npm install @inngest/middleware-sentry
import * as Sentry from "@sentry/node";
import { sentryMiddleware } from "@inngest/middleware-sentry";
Sentry.init({
/* your Sentry config */
});
const inngest = new Inngest({
id: "my-app",
middleware: [sentryMiddleware()]
});
例外をキャプチャし、各関数の実行にトレーシングを追加し、関数 ID とイベント名をコンテキストとして含めます。@sentry/*@>=8.0.0 が必要です。
一般的なミドルウェアパターン
メトリクスとパフォーマンスのトラッキング
const metricsMiddleware = new InngestMiddleware({
name: "Metrics Tracking",
init() {
return {
onFunctionRun({ ctx, fn }) {
let startTime: number;
return {
beforeExecution() {
startTime = Date.now();
metrics.increment("inngest.step.started", {
function: fn.id,
event: ctx.event.name
});
},
afterExecution() {
const duration = Date.now() - startTime;
metrics.histogram("inngest.step.duration", duration, {
function: fn.id,
event: ctx.event.name
});
},
transformOutput({ result }) {
const status = result.error ? "error" : "success";
metrics.increment("inngest.step.completed", {
function: fn.id,
status: status
});
return { result };
}
};
}
};
}
});
高度なパターン
認証: トークンを検証し、ユーザーコンテキストを注入します 条件付きロジック: イベントタイプや関数に基づいてミドルウェアを適用します サーキットブレーカー: 外部サービスからのカスケード障害を防ぎます
設定ベースのミドルウェア
さまざまな環境やユースケース向けの設定オプションを備えた再利用可能なミドルウェアを作成します。完全な例については、リファレンスドキュメントを参照してください。
ベストプラクティス
設計原則
- ミドルウェアを焦点を絞ったものにする: 1つのミドルウェアにつき1つの関心事
- エラーを適切に処理する: ミドルウェアで関数をクラッシュさせない
- パフォーマンスを考慮する: ミドルウェアは実行のたびに動作します
- 適切な型付けを使用する: TypeScript にミドルウェアの型を推論させる
- 徹底的にテストする: ミドルウェアはそれを使用するすべての関数に影響します
実装する一般的なユースケース
- 一時的な障害に対するリトライロジック
- 外部サービス呼び出しのサーキットブレーカー
- デバッグ用のリクエスト/レスポンスログ
- 外部ソースからのユーザーコンテキストの拡充
- 段階的なロールアウトのためのフィーチャーフラグ
- カスタム認証と認可チェック
ミドルウェアでのエラーハンドリング
const robustMiddleware = new InngestMiddleware({
name: "Robust Middleware",
init() {
return {
onFunctionRun({ ctx, fn }) {
return {
transformOutput({ result }) {
try {
// Your middleware logic here
return performTransformation(result);
} catch (middlewareError) {
// Log error but don't break the function
console.error("Middleware error:", middlewareError);
// Return original result on middleware failure
return { result };
}
}
};
}
};
}
});
ミドルウェアのテスト
Inngest のテストユーティリティ(createMockContext、createMockFunction)を使用して、ミドルウェアの動作を単体テストします。
完全な実装例と高度なパターンについては、以下を参照してください: