当需要为 TypeScript 项目添加持久化执行能力时使用——构建可重试的 Webhook 处理器、崩溃后仍能恢复的后台任务、定时任务或超出单个请求生命周期的长时间运行工作流。涵盖 Inngest SDK 安装、客户端配置、环境变量、服务端点(Next.js、Express、Hono、Fastify)、连接即工作模式以及本地开发服务器。
Inngest 设置
本技能从零开始在 TypeScript 项目中设置 Inngest,涵盖安装、客户端配置、连接模式和本地开发。
这些技能专注于 TypeScript。 对于 Python 或 Go,请参考 Inngest 文档 获取语言特定指南。核心概念适用于所有语言。
前提条件
- Node.js 18+(推荐 Node.js 22.4+ 以支持 WebSocket)
- TypeScript 项目
- 包管理器(npm、yarn、pnpm 或 bun)
步骤 1:安装 Inngest SDK
在项目中安装 inngest npm 包:
npm install inngest
# 或
yarn add inngest
# 或
pnpm add inngest
# 或
bun add inngest
步骤 2:创建 Inngest 客户端
创建一个共享的客户端文件,你将在整个代码库中导入它:
// src/inngest/client.ts
import { Inngest } from "inngest";
export const inngest = new Inngest({
id: "my-app" // 应用程序的唯一标识符(连字符式 slug)
});
// 重要提示:v4 默认使用 Cloud 模式。对于本地开发,请设置 INNGEST_DEV=1 环境变量。
// 否则,你的服务端点将返回 500(“处于云模式但未找到签名密钥”)。
// 在生产环境中,设置 INNGEST_SIGNING_KEY(Cloud 模式必需)。
关键配置选项
id(必需):应用程序的唯一标识符。使用连字符式 slug,如"my-app"或"user-service"eventKey:用于发送事件的事件密钥(优先使用INNGEST_EVENT_KEY环境变量)env:分支环境的环境名称isDev:强制 Dev 模式(true)或 Cloud 模式(false)。v4 默认使用 Cloud 模式,因此本地开发请设置INNGEST_DEV=1环境变量。切勿在源代码中硬编码isDev: true——它会在生产环境中静默失效。始终使用环境变量。signingKey:生产环境的签名密钥(优先使用INNGEST_SIGNING_KEY环境变量)。在 v4 中从serve()移至客户端signingKeyFallback:用于密钥轮换的回退签名密钥(优先使用INNGEST_SIGNING_KEY_FALLBACK环境变量)baseUrl:自定义 Inngest API 基础 URL(优先使用INNGEST_BASE_URL环境变量)logger:自定义日志记录器实例(例如 winston、pino)——在函数上下文中启用loggermiddleware:中间件数组(参见 inngest-middleware 技能)
使用 eventType() 的类型化事件
import { Inngest, eventType } from "inngest";
import { z } from "zod";
const signupCompleted = eventType("user/signup.completed", {
schema: z.object({
userId: z.string(),
email: z.string(),
plan: z.enum(["free", "pro"])
})
});
const orderPlaced = eventType("order/placed", {
schema: z.object({
orderId: z.string(),
amount: z.number()
})
});
export const inngest = new Inngest({ id: "my-app" });
// 使用事件类型作为触发器以实现完全类型安全:
inngest.createFunction(
{ id: "handle-signup", triggers: [signupCompleted] },
async ({ event }) => {
event.data.userId; /* 类型为 string */
}
);
// 发送事件时使用事件类型:
await inngest.send(
signupCompleted.create({
userId: "user_123",
email: "user@example.com",
plan: "pro"
})
);
环境变量设置
在 .env 文件或部署环境中设置这些环境变量:
# 生产环境必需
INNGEST_EVENT_KEY=your-event-key-here
INNGEST_SIGNING_KEY=your-signing-key-here
# 本地开发时强制开发模式
INNGEST_DEV=1
# 可选 - 自定义开发服务器 URL(默认:http://localhost:8288)
INNGEST_BASE_URL=http://localhost:8288
⚠️ 常见陷阱:切勿在源代码中硬编码密钥。始终使用环境变量设置 INNGEST_EVENT_KEY 和 INNGEST_SIGNING_KEY。
关键:为本地开发启用开发模式
在创建服务端点或连接工作进程之前,请确保已启用开发模式。 否则,Inngest 将默认使用 Cloud 模式,你的端点将失败并返回 500 错误。
添加到你的 .env 文件(或 package.json 中的开发脚本):
INNGEST_DEV=1
或者在 package.json 脚本中:
{
"scripts": {
"dev": "INNGEST_DEV=1 tsx --watch src/server.ts"
}
}
缺少 INNGEST_DEV 的症状:
- GET
/api/inngest返回{"code":"internal_server_error"} - 服务器日志:“处于云模式但未找到签名密钥”
- 开发服务器无法与你的应用同步
步骤 3:选择连接模式
Inngest 支持两种连接模式:
模式 A:服务端点(HTTP)
最适合无服务器平台(Vercel、Lambda 等)和现有 API。
模式 B:连接(WebSocket)
最适合容器运行时(Kubernetes、Docker)和长时间运行的进程。
步骤 4A:服务端点(HTTP 模式)
创建一个 API 端点,将你的函数暴露给 Inngest:
// 对于 Next.js App Router:src/app/api/inngest/route.ts
import { serve } from "inngest/next";
import { inngest } from "../../../inngest/client";
import { myFunction } from "../../../inngest/functions";
export const { GET, POST, PUT } = serve({
client: inngest,
functions: [myFunction]
});
// 对于 Next.js Pages Router:pages/api/inngest.ts
import { serve } from "inngest/next";
import { inngest } from "../../inngest/client";
import { myFunction } from "../../inngest/functions";
export default serve({
client: inngest,
functions: [myFunction]
});
// 对于 Express.js
import express from "express";
import { serve } from "inngest/express";
import { inngest } from "./inngest/client";
import { myFunction } from "./inngest/functions";
const app = express();
app.use(express.json({ limit: "10mb" })); // Inngest 必需,增加限制以支持更大的函数状态
app.use(
"/api/inngest",
serve({
client: inngest,
functions: [myFunction]
})
);
🔧 框架特定说明:
- Express:必须使用
express.json({ limit: "10mb" })中间件以支持更大的函数状态。 - Fastify:使用来自
inngest/fastify的fastifyPlugin - Cloudflare Workers:使用
inngest/cloudflare - AWS Lambda:使用
inngest/lambda - 对于所有其他框架,请在此处查看
serve参考:https://www.inngest.com/docs-markdown/learn/serving-inngest-functions
⚠️ v4 变更:像 signingKey、signingKeyFallback 和 baseUrl 这样的选项现在在 Inngest 客户端构造函数上配置,而不是在 serve() 上。serve() 函数只接受 client、functions 和 streaming。
⚠️ 常见陷阱:始终使用 /api/inngest 作为端点路径。这样可以实现自动发现。如果必须使用不同的路径,则需要使用 -u 标志手动配置发现。
步骤 4B:连接即工作(WebSocket 模式)
适用于维护持久连接的长时间运行应用程序:
// src/worker.ts
import { connect } from "inngest/connect";
import { inngest } from "./inngest/client";
import { myFunction } from "./inngest/functions";
(async () => {
const connection = await connect({
apps: [{ client: inngest, functions: [myFunction] }],
instanceId: process.env.HOSTNAME, // 唯一工作进程标识符
maxWorkerConcurrency: 10 // 最大并发步骤数
});
console.log("工作进程已连接:", connection.state);
// 优雅关闭处理
await connection.closed;
console.log("工作进程已关闭");
})();
连接模式的要求:
- Node.js 22.4+(或 Deno 1.4+、Bun 1.1+)以支持 WebSocket
- 长时间运行的服务器环境(非无服务器)
- 生产环境需要
INNGEST_SIGNING_KEY和INNGEST_EVENT_KEY - 在生产环境中,在
Inngest客户端上设置appVersion参数以支持滚动部署
v4 连接变更:
- 工作线程隔离默认启用——WebSocket 连接在工作线程中执行以防止事件循环饥饿。设置
isolateExecution: false以使用单进程(或INNGEST_CONNECT_ISOLATE_EXECUTION=false) rewriteGatewayEndpoint回调已被gatewayUrl字符串选项(或INNGEST_CONNECT_GATEWAY_URL环境变量)替代
步骤 5:使用应用组织
随着系统增长,将函数组织到逻辑应用中:
// 用户服务
const userService = new Inngest({ id: "user-service" });
// 支付服务
const paymentService = new Inngest({ id: "payment-service" });
// 邮件服务
const emailService = new Inngest({ id: "email-service" });
每个应用在 Inngest 仪表板中都有自己的部分,并且可以独立部署。使用描述性的、连字符式的 ID,与你的服务架构匹配。
⚠️ 常见陷阱:更改应用的 id 会在 Inngest 中创建一个新应用。保持 ID 在部署之间一致。
步骤 6:使用 inngest-cli 进行本地开发
启动 Inngest 开发服务器进行本地开发:
# 在常见端口/端点上自动发现你的应用
npx --ignore-scripts=false inngest-cli@latest dev
# 手动指定你的应用 URL
npx --ignore-scripts=false inngest-cli@latest dev -u http://localhost:3000/api/inngest
# 自定义开发服务器端口
npx --ignore-scripts=false inngest-cli@latest dev -p 9999
# 禁用自动发现
npx --ignore-scripts=false inngest-cli@latest dev --no-discovery -u http://localhost:3000/api/inngest
# 多个应用
npx --ignore-scripts=false inngest-cli@latest dev -u http://localhost:3000/api/inngest -u http://localhost:4000/api/inngest
开发服务器默认在 http://localhost:8288 可用。
配置文件(可选)
为复杂设置创建 inngest.json:
{
"sdk-url": [
"http://localhost:3000/api/inngest",
"http://localhost:4000/api/inngest"
],
"port": 8289,
"no-discovery": true
}
环境特定设置
本地开发
INNGEST_DEV=1
# 开发模式下无需密钥
生产环境
INNGEST_EVENT_KEY=evt_your_production_event_key
INNGEST_SIGNING_KEY=signkey_your_production_signing_key
自定义开发服务器端口
INNGEST_DEV=1
INNGEST_BASE_URL=http://localhost:9999
如果你的应用运行在非标准端口(不是 3000),请确保开发服务器可以通过 -u 标志指定 URL 来访问它。
常见问题与解决方案
端口冲突:如果端口 8288 已被占用,请指定不同的端口:-p 9999
自动发现不工作:使用手动 URL 指定:-u http://localhost:YOUR_PORT/api/inngest。如果使用 --no-discovery 标志,则 -u 标志是必需的——没有它,开发服务器将找不到你的应用。
函数未在开发服务器中显示:你的应用必须向开发服务器注册。当你的服务端点收到来自开发服务器的第一个请求时,这会自动发生。如果注册未发生:(1) 验证是否设置了 INNGEST_DEV=1,(2) 验证开发服务器能否访问你的应用 URL,(3) 尝试在开发服务器运行时重启你的应用。
签名验证错误:确保在生产环境中正确设置了 INNGEST_SIGNING_KEY
WebSocket 连接问题:验证 Node.js 版本为 22.4+ 以支持连接模式
Docker 开发:在 Docker 中运行开发服务器时,使用 host.docker.internal 作为应用 URL
下一步
- 使用
inngest.createFunction()创建你的第一个 Inngest 函数 - 使用开发服务器的“调用”按钮测试函数
- 使用
inngest.send()发送事件以触发函数 - 使用适当的环境变量部署到生产环境
- 参见 inngest-middleware 以添加日志记录、错误跟踪和其他横切关注点
- 在 Inngest 仪表板中监控函数
开发服务器会在你更改函数时自动重新加载,使开发快速且迭代。






