其他
在 Inngest v4…
当需要让日志、追踪、Sentry 错误追踪、敏感数据加密、客户端依赖注入等横切逻辑统一作用于 Inngest 函数时,使用 Inngest 中间件。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 57/100 ×0.15
适用场景
在 Inngest v4 中为持久化函数特定
解决思路
- 用 `InngestMiddleware` 创建自定义中间件:从 `inngest` 导入,实例化时传 `name` 和 `init()`;在 `init()` 中做初始化(例如创建 logger),返回生命周期 hooks 对象。
- 在 `onFunctionRun({ ctx, fn })` 中返回函数执行 hooks:`beforeExecution()` 记录函数开始(例如 functionId: fn.id、eventName: ctx.event.name、runId: ctx.runId);`afterExecution()` 记录函数完成;`transformOutput({ result })` 记录函数输出,并返回 `{ result }`。
- 在 `onSendEvent()` 中返回事件发送 hooks:`transformInput({ payloads })` 记录发送事件数量和名称,并返回 `{ payloads: [...payloads] }`,用 spread 把只读数组转为可变数组。
- 把中间件注册到 client-level 或 function-level:client 用 `new Inngest({ id, middleware: [...] })`;function 在 `createFunction({ id, middleware: [...], triggers: [...] }, async () => {})` 中配置。执行顺序为 client middleware 先运行,然后 function middleware,按数组中的顺序运行。
- 用内置 `dependencyInjectionMiddleware` 注入依赖:从 `inngest` 导入,在 client 的 `middleware` 数组里传入如 `openai: new OpenAI()`、`db: new PrismaClient()`;函数 handler 从参数解构 `{ event, openai, db }` 直接使用注入的客户端。
- 加密中间件:运行 `npm install @inngest/middleware-encryption`;从 `@inngest/middleware-encryption` 导入 `encryptionMiddleware`;在 client middleware 数组中使用 `encryptionMiddleware({ key: process.env.ENCRYPTION_KEY })`;它会自动加密所有 step data、function output 和 event 的 `data.encrypted` 字段;通过 `fallbackDecryptionKeys` 支持密钥轮换。
- Sentry 错误追踪:运行 `npm install @inngest/middleware-sentry`;从 `@sentry/node` 导入 `Sentry` 并调用 `Sentry.init({...})`;从 `@inngest/middleware-sentry` 导入 `sentryMiddleware`;在 client middleware 数组中加入 `sentryMiddleware()`;它会捕获异常、为每次 function run 添加 tracing,并把 function ID 和 event names 作为上下文;要求 `@sentry/*@>=8.0.0`。
- 实现指标和性能追踪中间件:用 `new InngestMiddleware({ name: 'Metrics Tracking', init() { return { onFunctionRun({ ctx, fn }) { let startTime; 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 }); return { result }; } }; } }; } })`。
- 实现认证中间件:在中间件中验证 tokens,并把用户上下文注入函数上下文。
- 实现条件逻辑中间件:根据 event type 或 function 决定是否应用中间件。
- 实现熔断器中间件:防止外部服务故障导致级联失败。
- 实现配置化中间件:为不同环境和用例创建带配置项的可复用中间件。
- 遵循设计原则:保持中间件聚焦,一个中间件只处理一个关注点。
- 优雅处理错误:不要让中间件导致函数崩溃。
- 考虑性能:中间件会在每次执行时运行。
- 使用正确类型:让 TypeScript 推断中间件类型。
- 充分测试:中间件会影响所有使用它的函数。
- 按常见用例实现:为瞬时失败实现 retry logic;为外部服务调用实现 circuit breakers;为调试实现 request/response logging;从外部来源做 user context enrichment;为渐进式发布加 feature flags;实现 custom authentication 和 authorization checks。
- 实现中间件错误处理模式:在 `transformOutput({ result })` 中用 `try/catch` 包裹中间件逻辑;在 `catch (middlewareError)` 中 `console.error('Middleware error:', middlewareError)`;失败时返回原始 `{ result }`,避免中间件错误破坏函数。
- 测试中间件:使用 Inngest 测试工具 `createMockContext`、`createMockFunction` 对中间件行为做单元测试。
适用边界 · 注意事项
- 不要在 Realtime 场景使用本技能:Inngest v4 原生支持 `step.realtime.publish`,无需 middleware;不要在 v4 项目安装 `@inngest/realtime`,它是 v3 时代包并会在运行时产生 `TypeError: Cls is not a constructor`,应改用 `inngest-realtime` skill。
- 非 TypeScript 项目不要直接套用这些 TypeScript hooks:Python 或 Go 应参考 Inngest 官方文档的语言特定指南,核心概念可借鉴。
- 从 v3 迁移时不要仅凭本技能判断细节:中间件系统在 v4 重写,应查阅 v3-to-v4 migration guide 中的 breaking changes。