在现代微服务和 Serverless 架构中,处理“异步任务”始终是一个痛点。传统的方案通常是:Redis + BullMQ,或者 AWS SQS + Lambda。但当你需要实现“在用户注册 24 小时后发送邮件”,或者“如果用户在 3 天内未激活则触发提醒”这种具有时间维度和状态依赖的复杂逻辑时,传统的队列方案会让你陷入“定时任务地狱”和“状态机噩梦”。
Inngest 提供了一种全新的方式:事件驱动的函数编排(Event-Driven Orchestration)。它允许你直接在代码中定义延迟、等待和条件分支,而无需管理底层的队列基础设施。
什么是 Inngest?
简单来说,Inngest 是一个可靠的事件队列和工作流引擎。它将你的业务逻辑(函数)与执行调度(触发、重试、延迟)解耦。
与传统的 Webhook 或 Queue 不同,Inngest 引入了“持久化执行”的概念。你不需要在数据库中记录“步骤 1 已完成,现在等待 2 小时”,你只需要在代码中写 step.sleep("2d"),Inngest 会在后台接管状态,并在时间到达时重新调用你的 API 接口。
核心特性
1. 声明式延迟与等待 (Sleep & Wait)
不再需要设置复杂的 Cron Job。你可以直接在函数内部定义等待时间。 - Sleep: 暂停执行,在指定时间后恢复。 - Wait: 等待某个特定事件发生后再继续。
2. 强大的重试机制与可靠性
如果你的下游 API 崩溃了,Inngest 会自动进行指数退避重试。由于状态是持久化的,即使你的服务器重启,工作流也会从失败的那个步骤精确恢复,而不是从头开始。
3. 扇入/扇出 (Fan-out / Fan-in)
你可以根据一个事件触发多个并行函数(扇出),也可以等待所有并行任务完成后再执行汇总操作(扇入)。
4. 可观测性控制台
Inngest 提供了一个极其强大的 UI,你可以实时看到每一个事件的流转过程,哪个步骤失败了,输入输出是什么,以及手动触发重试。
快速上手实例:构建一个“用户入职引导”流程
假设我们要实现这样一个场景: 1. 用户注册 \(\rightarrow\) 立即发送欢迎邮件。 2. 等待 1 天 \(\rightarrow\) 检查用户是否完成了个人资料填写。 3. 如果未完成 \(\rightarrow\) 发送提醒邮件。 4. 如果已完成 \(\rightarrow\) 发送高级功能指南。
1. 安装依赖
npm install inngest
2. 定义客户端与工作流
import { Inngest } from "inngest";
import { TRPC } from "./trpc"; // 假设你使用 TRPC 或其他 API 框架
// 创建 Inngest 客户端
const inngest = new Inngest({ id: "my-app-onboarding" });
// 定义一个事件驱动的函数
export const onboardingWorkflow = inngest.createFunction(
{
id: "user-onboarding-flow",
name: "User Onboarding Flow"
},
{
event: "app.user.signed_up" // 监听这个事件
},
async ({ event, step }) => {
// 步骤 1: 立即发送欢迎邮件
await step.run("send-welcome-email", async () => {
await sendEmail(event.data.email, "Welcome to our App!");
return { sent: true };
});
// 步骤 2: 暂停执行 24 小时
await step.sleep("wait-one-day", "1d");
// 步骤 3: 检查用户状态
const userStatus = await step.run("check-profile-completion", async () => {
const user = await db.user.findUnique({ where: { id: event.data.userId } });
return user.profileCompleted;
});
if (!userStatus) {
// 步骤 4a: 发送提醒
await step.run("send-reminder-email", async () => {
await sendEmail(event.data.email, "Complete your profile to get started!");
});
} else {
// 步骤 4b: 发送高级指南
await step.run("send-pro-guide", async () => {
await sendEmail(event.data.email, "Check out these pro tips!");
});
}
}
);
3. 触发事件
在你的注册接口中,你只需要发送一个事件,而不需要关心后续复杂的逻辑:
await inngest.send({
name: "app.user.signed_up",
event: {
userId: "user_123",
email: "hello@example.com",
},
});
Inngest 与传统消息队列 (如 RabbitMQ/BullMQ) 的区别
| 特性 | 传统队列 (BullMQ/SQS) | Inngest |
|---|---|---|
| 状态管理 | 需要手动在 DB 记录任务进度 | 自动持久化,代码即状态 |
| 延迟执行 | 依赖延迟队列或定时扫描 | 声明式 step.sleep() |
| 可见性 | 难以追踪单个请求的完整链路 | 完整的可视化执行轨迹 (Trace) |
| 基础设施 | 需要维护 Redis/Broker 实例 | Serverless 模式,通过 HTTP 触发 |
| 重试粒度 | 通常是整个 Job 重试 | 仅重试失败的特定 step |
适用场景
- 复杂的营销自动化:基于用户行为触发的阶梯式邮件/推送序列。
- 数据同步与 ETL:需要分步骤处理大量数据,且每一步都需要保证可靠性的场景。
- 第三方 API 编排:调用多个不稳定的外部 API,需要精细控制重试和超时。
- Serverless 架构:在 Vercel, Netlify, Cloudflare Workers 等环境下,无法运行常驻进程(如 BullMQ 消费者)时,Inngest 是绝佳选择。
总结
Inngest 将“分布式系统”的复杂性(状态机、重试、定时器)从你的业务代码中抽离了出来。它让你能够像写同步代码一样编写异步工作流,同时获得了企业级的可靠性和可观测性。如果你厌倦了在数据库里写 next_run_at 字段,或者在处理分布式事务时感到头疼,Inngest 值得一试。



还没有评论,来说两句吧...