inngest-setup

inngest-setup

当需要为 TypeScript 项目添加持久化执行能力时使用——构建可重试的 Webhook 处理器、崩溃后仍能恢复的后台任务、定时任务或超出单个请求生命周期的长时间运行工作流。涵盖 Inngest SDK 安装、客户端配置、环境变量、服务端点(Next.js、Express、Hono、Fastify)、连接即工作模式以及本地开发服务器。

26Star
5Fork
更新于 2026/7/2
SKILL.md
readonly只读
name
inngest-setup
description

当需要为 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)——在函数上下文中启用 logger
  • middleware:中间件数组(参见 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_KEYINNGEST_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/fastifyfastifyPlugin
  • Cloudflare Workers:使用 inngest/cloudflare
  • AWS Lambda:使用 inngest/lambda
  • 对于所有其他框架,请在此处查看 serve 参考:https://www.inngest.com/docs-markdown/learn/serving-inngest-functions

⚠️ v4 变更:像 signingKeysigningKeyFallbackbaseUrl 这样的选项现在在 Inngest 客户端构造函数上配置,而不是在 serve() 上。serve() 函数只接受 clientfunctionsstreaming

⚠️ 常见陷阱:始终使用 /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_KEYINNGEST_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

下一步

  1. 使用 inngest.createFunction() 创建你的第一个 Inngest 函数
  2. 使用开发服务器的“调用”按钮测试函数
  3. 使用 inngest.send() 发送事件以触发函数
  4. 使用适当的环境变量部署到生产环境
  5. 参见 inngest-middleware 以添加日志记录、错误跟踪和其他横切关注点
  6. 在 Inngest 仪表板中监控函数

开发服务器会在你更改函数时自动重新加载,使开发快速且迭代。