inngest-setup

inngest-setup

當你需要在 TypeScript 專案中加入持久化執行(durable execution)時使用——建立可重試的 Webhook 處理器、能在崩潰後繼續執行的背景任務、排程工作,或是跨越單一請求的長時間工作流程。涵蓋 Inngest SDK 安裝、客戶端設定、環境變數、serve 端點(Next.js、Express、Hono、Fastify)、connect-as-worker 模式以及本機開發伺服器。

26星標
5分支
更新於 2026/7/2
SKILL.md
唯讀
名稱
inngest-setup
描述

當你需要在 TypeScript 專案中加入持久化執行(durable execution)時使用——建立可重試的 Webhook 處理器、能在崩潰後繼續執行的背景任務、排程工作,或是跨越單一請求的長時間工作流程。涵蓋 Inngest SDK 安裝、客戶端設定、環境變數、serve 端點(Next.js、Express、Hono、Fastify)、connect-as-worker 模式以及本機開發伺服器。

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 環境變數。
// 若未設定,serve 端點會回傳 500(「在 Cloud 模式下但未提供 signing key」)。
// 正式環境需設定 INNGEST_SIGNING_KEY(Cloud 模式必要)。

主要設定選項

  • id(必要):應用程式的唯一識別碼。使用連字號 slug,例如 "my-app""user-service"
  • eventKey:用於傳送事件的 Event Key(建議使用 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:自訂的 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

# 本機開發時強制 Dev 模式
INNGEST_DEV=1

# 選用 - 自訂開發伺服器 URL(預設:http://localhost:8288)
INNGEST_BASE_URL=http://localhost:8288

⚠️ 常見陷阱:切勿在原始碼中寫死金鑰。請一律使用環境變數來設定 INNGEST_EVENT_KEYINNGEST_SIGNING_KEY

關鍵:啟用 Dev 模式以進行本機開發

在建立 serve 端點或連線 worker 之前,請確認 Dev 模式已啟用。 若未啟用,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"}
  • 伺服器日誌:「在 Cloud 模式下但未提供 signing key」
  • 開發伺服器無法與應用程式同步

步驟 3:選擇連線模式

Inngest 支援兩種連線模式:

模式 A:Serve 端點(HTTP)

最適合無伺服器平台(Vercel、Lambda 等)和現有 API。

模式 B:Connect(WebSocket)

最適合容器執行環境(Kubernetes、Docker)和長時間執行的程序。

步驟 4A:提供 Serve 端點(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 變更: signingKeysigningKeyFallbackbaseUrl 等選項現在是在 Inngest 客戶端建構函式中設定,而非 serve()serve() 函式僅接受 clientfunctionsstreaming

⚠️ 常見陷阱:請一律使用 /api/inngest 作為端點路徑。這樣可以啟用自動探索。如果必須使用其他路徑,則需要使用 -u 標記手動設定探索。

步驟 4B:以 Worker 連線(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, // 唯一的 worker 識別碼
    maxWorkerConcurrency: 10 // 最大並行步驟數
  });

  console.log("Worker 已連線:", connection.state);

  // 優雅關機處理
  await connection.closed;
  console.log("Worker 已關閉");
})();

Connect 模式的需求

  • Node.js 22.4+(或 Deno 1.4+、Bun 1.1+)以支援 WebSocket
  • 長時間執行的伺服器環境(非無伺服器)
  • 正式環境需要 INNGEST_SIGNING_KEYINNGEST_EVENT_KEY
  • 在正式環境中,在 Inngest 客戶端上設定 appVersion 參數以支援滾動部署

v4 Connect 變更:

  • Worker 執行緒隔離預設啟用——WebSocket 連線在 worker 執行緒中執行,以防止事件迴圈飢餓。設定 isolateExecution: false 以使用單一程序(或 INNGEST_CONNECT_ISOLATE_EXECUTION=false
  • rewriteGatewayEndpoint 回呼已被 gatewayUrl 字串選項取代(或 INNGEST_CONNECT_GATEWAY_URL 環境變數)

步驟 5:使用 Apps 組織

隨著系統成長,將函式組織成邏輯上的 apps:

// 使用者服務
const userService = new Inngest({ id: "user-service" });

// 付款服務
const paymentService = new Inngest({ id: "payment-service" });

// 電子郵件服務
const emailService = new Inngest({ id: "email-service" });

每個 app 在 Inngest 儀表板中都會有自己的區塊,並且可以獨立部署。使用描述性、連字號的 ID,並與你的服務架構相符。

⚠️ 常見陷阱:變更 app 的 id 會在 Inngest 中建立一個新的 app。請保持 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
# Dev 模式不需要金鑰

正式環境

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 標記是必要的——開發伺服器將無法找到你的應用程式。

函式未顯示在開發伺服器中:你的應用程式必須向開發伺服器註冊。當你的 serve 端點收到來自開發伺服器的第一個請求時,這會自動發生。如果註冊未發生:(1) 確認已設定 INNGEST_DEV=1,(2) 確認開發伺服器可以連線到你的應用程式 URL,(3) 嘗試在開發伺服器執行時重新啟動你的應用程式。

簽章驗證錯誤:確保在正式環境中正確設定 INNGEST_SIGNING_KEY

WebSocket 連線問題:確認 Node.js 版本為 22.4+ 以使用 connect 模式

Docker 開發:當開發伺服器在 Docker 中執行時,應用程式 URL 請使用 host.docker.internal

後續步驟

  1. 使用 inngest.createFunction() 建立你的第一個 Inngest 函式
  2. 使用開發伺服器的「Invoke」按鈕測試函式
  3. 使用 inngest.send() 傳送事件以觸發函式
  4. 使用適當的環境變數部署到正式環境
  5. 參閱 inngest-middleware 以了解如何加入日誌、錯誤追蹤和其他橫切關注點
  6. 在 Inngest 儀表板中監控函式

開發伺服器會在函式變更時自動重新載入,使開發快速且迭代。