教程 / 后端集成 / 使用 Inngest 处理后台任务
📝 文字 ● 中级 更新于 2026-05-13

使用 Inngest 处理后台任务

当服务器需要"稍后执行某项操作"时,过去你需要搭建 Redis、BullMQ、一个 worker 进程以及一整套部署方案。Inngest 用一个函数和一个事件取代了这一切。内置持久化重试,无需管理基础设施,支持 serverless。

它取代了什么

0

这些操作应该在用户请求返回之后执行:

  • 注册后发送欢迎邮件。
  • 生成 PDF 报告。
  • 处理视频上传。
  • 向多个收件人广播通知。
  • 将数据同步到第三方 API,失败时自动重试。

传统方案:Redis + BullMQ + worker 进程。现代 serverless 方案:Inngest、Trigger.dev ↗Temporal ↗。本教程选用 Inngest,因为它的开发者体验对初学者最友好。

注册 + 创建应用

1

前往 app.inngest.com ↗ 注册。免费套餐:每月 10 万次事件 + 1K 并发运行——对早期项目来说完全够用。

控制台 → Apps → 首次连接时会自动创建你的应用。后面我们会回到这里。

安装 SDK

2
npm install inngest

其他运行时:Python ↗Go ↗。以下示例使用 JS。

定义第一个函数

3

Inngest 函数就是普通的异步函数,由命名事件触发。

// inngest/functions.js
import { Inngest } from "inngest";

export const inngest = new Inngest({ id: "my-app" });

export const sendWelcomeEmail = inngest.createFunction(
  { id: "send-welcome-email" },
  { event: "user/signed-up" },
  async ({ event, step }) => {
    const { email } = event.data;

    // Each `step.run` is durable — retried independently on failure
    const customer = await step.run("create-customer", async () => {
      return createStripeCustomer(email);
    });

    await step.run("send-email", async () => {
      return sendResendEmail({
        to: email,
        subject: "Welcome",
        body: `Hi! Customer ID: ${customer.id}`,
      });
    });
  }
);

挂载处理器

4

添加一个 HTTP 端点,让 Inngest 调用你的函数。各框架写法如下:

Next.js(App Router):

// app/api/inngest/route.ts
import { serve } from "inngest/next";
import { inngest, sendWelcomeEmail } from "@/inngest/functions";

export const { GET, POST, PUT } = serve({
  client: inngest,
  functions: [sendWelcomeEmail],
});

Express:

import { serve } from "inngest/express";
import express from "express";

const app = express();
app.use(express.json());
app.use("/api/inngest", serve({
  client: inngest,
  functions: [sendWelcomeEmail],
}));

完整框架列表:Serving functions ↗。Vercel、Cloudflare Workers、Hono、Fastify、Remix、Astro、NestJS、AWS Lambda——均已支持。

发送事件

5

在应用的任意位置调用——API 路由、webhook 处理器、cron 任务都行:

import { inngest } from "@/inngest/functions";

await inngest.send({
  name: "user/signed-up",
  data: { email: "[email protected]" },
});

立即返回,只需几毫秒。用户请求快速响应,后续执行交给 Inngest。

使用开发服务器在本地运行

6

Inngest 内置本地开发服务器——无需 Docker,直接在终端运行:

npx inngest-cli@latest dev

访问 http://localhost:8288。开发服务器会自动发现你的 /api/inngest 端点,列出所有函数,支持从 UI 触发事件,并以步骤为单位展示执行追踪和重试行为。全程不离开本机,实时调试。

连接到生产环境

7

部署应用后,在 Inngest 控制台 → Apps → Sync new app → 粘贴以 /api/inngest 结尾的生产 URL。Inngest 会自动探测并发现你的函数,随后开始路由事件。

在生产环境添加以下环境变量:

INNGEST_EVENT_KEY=...    # for inngest.send() to authenticate
INNGEST_SIGNING_KEY=...  # for Inngest to verify it's calling YOUR app

两个密钥均可在控制台的 Settings → Keys 中查看。

进阶模式(省去你自己手搓的功夫)

8

休眠 / 延迟。在函数内等待数小时甚至数天;等待期间 Inngest 不会让你的服务器保持常驻。

await step.sleep("wait-a-day", "24h");
await step.run("send-reminder", () => sendEmail(...));
9

等待事件。暂停执行,直到特定事件到达。适合"用户 24 小时内未确认则发送提醒"的场景。

const confirmation = await step.waitForEvent("wait-for-confirm", {
  event: "user/email-confirmed",
  timeout: "24h",
  match: "data.userId",
});

if (!confirmation) {
  await step.run("send-nudge", () => sendNudgeEmail(...));
}
10

定时任务(cron)。

export const dailyDigest = inngest.createFunction(
  { id: "daily-digest" },
  { cron: "0 8 * * *" },     // every day at 08:00 UTC
  async ({ step }) => {
    await step.run("send-digest", () => sendDigestToAllUsers());
  }
);
11

广播(Fan-out)。一个事件触发 N 个并行函数:

// Two functions, both listening for the same event
export const a = inngest.createFunction({ id: "a" }, { event: "order/paid" }, ...);
export const b = inngest.createFunction({ id: "b" }, { event: "order/paid" }, ...);

// One send triggers both
await inngest.send({ name: "order/paid", data: {...} });
12

并发限制 + 限流。限制同时执行的运行数量(例如针对有速率限制的第三方 API):

inngest.createFunction(
  {
    id: "process-image",
    concurrency: { limit: 5 },                  // at most 5 at once globally
    throttle: { limit: 100, period: "1m" },     // and no more than 100/min
  },
  { event: "image/uploaded" },
  async ({ event, step }) => { /* ... */ }
);

重试是自动的

13

如果某个 step.run 抛出异常,Inngest 会以指数退避方式自动重试(默认 4 次,约 10 分钟内完成)。已成功的步骤不会重新执行——只有失败的步骤才会重试。可按函数配置:

inngest.createFunction(
  { id: "syncs", retries: 10 },
  { event: "user/created" },
  async ({ event, step }) => { ... }
);

抛出 NonRetriableError 可立即终止,不再重试(例如输入无效——重试也没有意义)。

常见坑

14
  • 忘记用 step.run 包裹——在 step.run 外部的代码每次重试都会重新执行。数据库写入、API 调用等副作用必须放在 step 内部。
  • 事件 payload 过大——事件有大小限制(通常为 512 KB)。大数据请存到 S3/R2,只传 URL。
  • Vercel 上的长耗时步骤——Vercel 会在 10–60 秒后(取决于套餐)终止函数。Inngest 步骤遵循这一限制——将任务拆分成更小的 step.run,Inngest 会将它们作为独立调用执行。
  • 忘记挂载处理器——事件可以正常流入 Inngest,但在 Inngest 能调用你的端点之前,函数无法执行。开发服务器在无法访问时会打印友好的错误提示。
Inngest 对"事件即名词/动词"的模式有明确约定。推荐使用 user/signed-uporder/paidimage/uploaded 这样的事件命名。函数响应事件,事件就是 API。这种思维方式便于推理,但需要一点时间内化。事件指南 ↗

定价实际情况

15

免费套餐:每月 10 万次事件 + 1K 并发运行,早期项目绰绰有余。付费版起价 $50/月。Inngest 定价 ↗

自托管:Inngest 开源了社区版 ↗。生产环境自托管需要一定运维投入。

官方参考资料

接下来学什么