本文へ移動
cccskills
無料GitHub で公開

inngest-events

Use when designing event-driven workflows, decoupling services, implementing fan-out patterns (one trigger, many downstream handlers), implementing idempotent event handling with IDs (24-hour dedupe window), or handling at-least-once delivery from external sources like Stripe webhooks. Covers Inngest event schema, payload format, naming conventions, IDs for idempotency, the ts param, fan-out patterns, and system events like inngest/function.failed.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md11.8 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Inngest Events

Master Inngest event design and delivery patterns. Events are the foundation of Inngest - learn to design robust event schemas, implement idempotency, leverage fan-out patterns, and handle system events effectively.

These skills are focused on TypeScript. For Python or Go, refer to the Inngest documentation for language-specific guidance. Core concepts apply across all languages.

Event Payload Format

Every Inngest event is a JSON object with required and optional properties:

Required Properties

type Event = {
  name: string; // Event type (triggers functions)
  data: object; // Payload data (any nested JSON)
};

Complete Schema

type EventPayload = {
  name: string; // Required: event type
  data: Record<string, any>; // Required: event data
  id?: string; // Optional: deduplication ID
  ts?: number; // Optional: timestamp (Unix ms)
  v?: string; // Optional: schema version
};

Basic Event Example

await inngest.send({
  name: "billing/invoice.paid",
  data: {
    customerId: "cus_NffrFeUfNV2Hib",
    invoiceId: "in_1J5g2n2eZvKYlo2C0Z1Z2Z3Z",
    userId: "user_03028hf09j2d02",
    amount: 1000,
    metadata: {
      accountId: "acct_1J5g2n2eZvKYlo2C0Z1Z2Z3Z",
      accountName: "Acme.ai"
    }
  }
});

Event Naming Conventions

Use the Object-Action pattern: domain/noun.verb

Recommended Patterns

// ✅ Good: Clear object-action pattern
"billing/invoice.paid";
"user/profile.updated";
"order/item.shipped";
"ai/summary.completed";

// ✅ Good: Domain prefixes for organization
"stripe/customer.created";
"intercom/conversation.assigned";
"slack/message.posted";

// ❌ Avoid: Unclear or inconsistent
"payment"; // What happened?
"user_update"; // Use dots, not underscores
"invoiceWasPaid"; // Too verbose

Naming Guidelines

  • Past tense: Events describe what happened (created, updated, failed)
  • Dot notation: Use dots for hierarchy (billing/invoice.paid)
  • Prefixes: Group related events (api/user.created, webhook/stripe.received)
  • Consistency: Establish patterns and stick to them

Event IDs and Idempotency

When to use IDs: Prevent duplicate processing when events might be sent multiple times.

Basic Deduplication

await inngest.send({
  id: "cart-checkout-completed-ed12c8bde", // Unique per event type
  name: "storefront/cart.checkout.completed",
  data: {
    cartId: "ed12c8bde",
    items: ["item1", "item2"]
  }
});

ID Best Practices

// ✅ Good: Specific to event type and instance
id: `invoice-paid-${invoiceId}`;
id: `user-signup-${userId}-${timestamp}`;
id: `order-shipped-${orderId}-${trackingNumber}`;

// ❌ Bad: Generic IDs shared across event types
id: invoiceId; // Could conflict with other events
id: "user-action"; // Too generic
id: customerId; // Same customer, different events

Deduplication window: 24 hours from first event reception

See inngest-durable-functions for idempotency configuration.

The ts Parameter for Delayed Delivery

When to use: Schedule events for future processing or maintain event ordering.

Future Scheduling

const oneHourFromNow = Date.now() + 60 * 60 * 1000;

await inngest.send({
  name: "trial/reminder.send",
  ts: oneHourFromNow, // Deliver in 1 hour
  data: {
    userId: "user_123",
    trialExpiresAt: "2024-02-15T12:00:00Z"
  }
});

Maintaining Event Order

// Events with timestamps are processed in chronological order
const events = [
  {
    name: "user/action.performed",
    ts: 1640995200000, // Earlier
    data: { action: "login" }
  },
  {
    name: "user/action.performed",
    ts: 1640995260000, // Later
    data: { action: "purchase" }
  }
];

await inngest.send(events);

Fan-Out Patterns

Use case: One event triggers multiple independent functions for reliability and parallel processing.

Basic Fan-Out Implementation

// Send single event
await inngest.send({
  name: "user/signup.completed",
  data: {
    userId: "user_123",
    email: "user@example.com",
    plan: "pro"
  }
});

// Multiple functions respond to same event
const sendWelcomeEmail = inngest.createFunction(
  { id: "send-welcome-email", triggers: [{ event: "user/signup.completed" }] },
  async ({ event, step }) => {
    await step.run("send-email", async () => {
      return sendEmail({
        to: event.data.email,
        template: "welcome"
      });
    });
  }
);

const createTrialSubscription = inngest.createFunction(
  { id: "create-trial", triggers: [{ event: "user/signup.completed" }] },
  async ({ event, step }) => {
    await step.run("create-subscription", async () => {
      return stripe.subscriptions.create({
        customer: event.data.stripeCustomerId,
        trial_period_days: 14
      });
    });
  }
);

const addToCrm = inngest.createFunction(
  { id: "add-to-crm", triggers: [{ event: "user/signup.completed" }] },
  async ({ event, step }) => {
    await step.run("crm-sync", async () => {
      return crm.contacts.create({
        email: event.data.email,
        plan: event.data.plan
      });
    });
  }
);

Fan-Out Benefits

  • Independence: Functions run separately; one failure doesn't affect others
  • Parallel execution: All functions run simultaneously
  • Selective replay: Re-run only failed functions
  • Cross-service: Trigger functions in different codebases/languages

Advanced Fan-Out with waitForEvent

In expressions, event = the original triggering event, async = the new event being matched. See Expression Syntax Reference for full details.

const orchestrateOnboarding = inngest.createFunction(
  { id: "orchestrate-onboarding", triggers: [{ event: "user/signup.completed" }] },
  async ({ event, step }) => {
    // Fan out to multiple services
    await step.sendEvent("fan-out", [
      { name: "email/welcome.send", data: event.data },
      { name: "subscription/trial.create", data: event.data },
      { name: "crm/contact.add", data: event.data }
    ]);

    // Wait for all to complete
    const [emailResult, subResult, crmResult] = await Promise.all([
      step.waitForEvent("email-sent", {
        event: "email/welcome.sent",
        timeout: "5m",
        if: `event.data.userId == async.data.userId`
      }),
      step.waitForEvent("subscription-created", {
        event: "subscription/trial.created",
        timeout: "5m",
        if: `event.data.userId == async.data.userId`
      }),
      step.waitForEvent("crm-synced", {
        event: "crm/contact.added",
        timeout: "5m",
        if: `event.data.userId == async.data.userId`
      })
    ]);

    // Complete onboarding
    await step.run("complete-onboarding", async () => {
      return completeUserOnboarding(event.data.userId);
    });
  }
);

See inngest-steps for additional patterns including step.invoke.

System Events

Inngest emits system events for function lifecycle monitoring:

Available System Events

// Function execution events
"inngest/function.failed"; // Function failed after retries
"inngest/function.finished"; // Function finished - completed or failed
"inngest/function.cancelled"; // Function cancelled before completion

Handling Failed Functions

const handleFailures = inngest.createFunction(
  { id: "handle-failed-functions", triggers: [{ event: "inngest/function.failed" }] },
  async ({ event, step }) => {
    const { function_id, run_id, error } = event.data;

    await step.run("log-failure", async () => {
      logger.error("Function failed", {
        functionId: function_id,
        runId: run_id,
        error: error.message,
        stack: error.stack
      });
    });

    // Alert on critical function failures
    if (function_id.includes("critical")) {
      await step.run("send-alert", async () => {
        return alerting.sendAlert({
          title: `Critical function failed: ${function_id}`,
          severity: "high",
          runId: run_id
        });
      });
    }

    // Auto-retry certain failures
    if (error.code === "RATE_LIMIT_EXCEEDED") {
      await step.run("schedule-retry", async () => {
        return inngest.send({
          name: "retry/function.requested",
          ts: Date.now() + 5 * 60 * 1000, // Retry in 5 minutes
          data: { originalRunId: run_id }
        });
      });
    }
  }
);

Sending Events

Client Setup

// inngest/client.ts
import { Inngest } from "inngest";

export const inngest = new Inngest({
  id: "my-app"
});
// You must set INNGEST_EVENT_KEY environment variable in production

Single Event

const result = await inngest.send({
  name: "order/placed",
  data: {
    orderId: "ord_123",
    customerId: "cus_456",
    amount: 2500,
    items: [
      { id: "item_1", quantity: 2 },
      { id: "item_2", quantity: 1 }
    ]
  }
});

// Returns event IDs for tracking
console.log(result.ids); // ["01HQ8PTAESBZPBDS8JTRZZYY3S"]

Batch Events

const orderItems = await getOrderItems(orderId);

// Convert to events
const events = orderItems.map((item) => ({
  name: "inventory/item.reserved",
  data: {
    itemId: item.id,
    orderId: orderId,
    quantity: item.quantity,
    warehouseId: item.warehouseId
  }
}));

// Send all at once (up to 512kb)
await inngest.send(events);

Sending from Functions

inngest.createFunction(
  { id: "process-order", triggers: [{ event: "order/placed" }] },
  async ({ event, step }) => {
    // Use step.sendEvent() instead of inngest.send() in functions
    // for reliability and deduplication
    await step.sendEvent("trigger-fulfillment", {
      name: "fulfillment/order.received",
      data: {
        orderId: event.data.orderId,
        priority: event.data.customerTier === "premium" ? "high" : "normal"
      }
    });
  }
);

Event Design Best Practices

Schema Versioning

// Use version field to track schema changes
await inngest.send({
  name: "user/profile.updated",
  v: "2024-01-15.1", // Schema version
  data: {
    userId: "user_123",
    changes: {
      email: "new@example.com",
      preferences: { theme: "dark" }
    },
    // New field in v2 schema
    auditInfo: {
      changedBy: "user_456",
      reason: "user_requested"
    }
  }
});

Rich Context Data

// Include enough context for all consumers
await inngest.send({
  name: "payment/charge.succeeded",
  data: {
    // Primary identifiers
    chargeId: "ch_123",
    customerId: "cus_456",

    // Amount details
    amount: 2500,
    currency: "usd",

    // Context for different consumers
    subscription: {
      id: "sub_789",
      plan: "pro_monthly"
    },
    invoice: {
      id: "inv_012",
      number: "INV-2024-001"
    },

    // Metadata for debugging
    paymentMethod: {
      type: "card",
      last4: "4242",
      brand: "visa"
    },
    metadata: {
      source: "stripe_webhook",
      environment: "production"
    }
  }
});

Event design principles:

  1. Self-contained: Include all data consumers need
  2. Immutable: Never modify event schemas after sending
  3. Traceable: Include correlation IDs and audit trails
  4. Actionable: Provide enough context for business logic
  5. Debuggable: Include metadata for troubleshooting

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use when building, migrating, or debugging Agent Evals on Inngest: scoring AI agent or workflow outcomes, deferred scorers, sessions, traces, step experiments, experiment variant attribution, Insights queries, or production eval loops for prompts, models, tools, providers, and agent behavior. Covers TypeScript SDK v4 scoring beta APIs, `scoreMiddleware`, `step.score`, `inngest.score`, `createScorer`, `defer`, `group.experiment`, `experimentRef`, `meta.sessions`, and when to use durable workflow primitives for outcome-based evaluation.

日本語の概要は準備中です。原文の説明を表示しています。

inngest/inngest-skills282026年9月29日 更新

Use when building durable AI agents or agentic workflows with Inngest and AgentKit, including model calls, tool calls, multi-agent networks, human approval, realtime progress, provider rate limits, crash-safe execution, and Agent Evals handoff. Covers AgentKit, `step.ai`, `step.run`, `step.waitForEvent`, native realtime, and when to use lower-level Inngest primitives instead of an in-memory agent loop. Use `inngest-agent-evals` with this skill when the user wants scoring, sessions, experiments, deferred scorers, or outcome-based evaluation for the agent.

日本語の概要は準備中です。原文の説明を表示しています。

inngest/inngest-skills282026年9月29日 更新

Use when the user explicitly asks for the Inngest REST API v2, raw HTTP, OpenAPI, API docs, API authentication, or an endpoint that the Inngest CLI does not expose. Covers api-docs.inngest.com, llms.txt, the OpenAPI v2 spec, Bearer authentication with API keys or signing keys, production and local base URLs, raw curl/fetch requests, request-shape discovery, pagination, secret redaction, and when to prefer the `inngest-api-cli` skill instead.

日本語の概要は準備中です。原文の説明を表示しています。

inngest/inngest-skills282026年9月29日 更新

Use when operating Inngest API resources from the terminal with `npx inngest-cli@latest api`: Cloud/local run debugging, event-run lookup, function traces, function invocation, app syncs, webhooks, environments, keys, account checks, and Insights queries. Provides prescriptive command routing for agents: which CLI command to run for a run ID, event ID, app ID, function ID, Cloud environment, API key, missing ID, or potentially mutating operation. Use `inngest-cli` for dev server setup/general CLI workflows and `inngest-api` only when raw REST API v2 docs or OpenAPI fallback are needed.

日本語の概要は準備中です。原文の説明を表示しています。

inngest/inngest-skills282026年9月29日 更新

Use when analyzing an existing TypeScript or JavaScript codebase to decide where and how to introduce Inngest. Covers repository discovery, framework and package detection, finding durability gaps in HTTP handlers, webhooks, cron jobs, queues, long-running jobs, AI agents, Agent Evals, polling loops, eval loops, and side-effect-heavy code, then producing and implementing an incremental integration plan.

日本語の概要は準備中です。原文の説明を表示しています。

inngest/inngest-skills282026年9月29日 更新

Use when installing or running the Inngest CLI and Dev Server for local development, local testing, serve endpoint debugging, Docker or Docker Compose setup, MCP configuration, self-hosted `inngest start`, or deployment workflow checks. Covers `inngest dev`, `inngest start`, auto-discovery, config files, environment variables, `@inngest/test`, local event sending, platform gotchas, and production/self-hosted server flags.

日本語の概要は準備中です。原文の説明を表示しています。

inngest/inngest-skills282026年9月29日 更新

inngest のスキルをすべて見る

このスキルの問題を報告する