关于 inngest-middleware
面向 Inngest TypeScript 开发者的中间件指南,介绍生命周期钩子及跨函数共享逻辑的实现方式,涵盖依赖注入、错误跟踪和数据转换。
主要功能
- 01客户端级与函数级中间件
- 02依赖注入
- 03加密与 Sentry 错误跟踪
- 04指标与性能追踪
- 05中间件行为测试
适用场景
- 01为函数添加日志和指标
- 02跨函数共享客户端实例
- 03加密步骤数据并跟踪异常
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ joelhooks/ joelclaw --skill inngest-middleware安装后在 Claude Code 中输入/inngest-middleware确认已加载。
详细介绍
Inngest 中间件
掌握 Inngest 中间件,以处理日志记录、错误跟踪、依赖注入和数据转换等横切关注点。中间件会在函数生命周期的关键节点运行,从而实现强大的可观测性和共享功能模式。
这些技能侧重于 TypeScript。 对于 Python 或 Go,请参阅 Inngest 文档中的语言特定指南。核心概念适用于所有语言。
什么是中间件?
中间件允许代码在 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
]
},
{ 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" },
{ 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 };
}
};
}
};
}
});
高级模式
身份验证: 验证令牌并注入用户上下文
条件逻辑: 根据事件类型或函数应用中间件
熔断器: 防止外部服务发生级联故障
基于配置的中间件
创建带有配置选项的可复用中间件,以适应不同的环境和使用场景。完整示例请参阅参考文档。
最佳实践
设计原则
- 保持中间件专注: 每个中间件只处理一个关注点
- 选择失败策略: 可选遥测功能可以优雅降级。身份验证、授权、验证和加密失败时必须拒绝访问。
- 考虑性能: 中间件会在每次执行时运行
- 使用正确的类型: 让 TypeScript 推断中间件类型
- 充分测试: 中间件会影响所有使用它的函数
常见实现用例
- 重试逻辑,用于处理暂时性故障
- 熔断器,用于外部服务调用
- 请求/响应日志记录,用于调试
- 从外部来源丰富用户上下文
- 功能标志,用于逐步发布
- 自定义身份验证和授权检查
中间件中的错误处理
const optionalTelemetryMiddleware = new InngestMiddleware({
name: "Optional Telemetry Middleware",
init() {
return {
onFunctionRun({ ctx, fn }) {
return {
transformOutput({ result }) {
try {
// Your middleware logic here
return performTransformation(result);
} catch (middlewareError) {
// This example is optional telemetry only; required guards must throw.
console.error("Middleware error:", middlewareError);
// Optional telemetry only. Security/validation middleware must propagate failure.
return { result };
}
}
};
}
};
}
});
测试中间件
使用 Inngest 的测试工具(createMockContext、createMockFunction)对中间件行为进行单元测试。
完整实现示例和高级模式请参阅: