Was macht inngest-durable-functions?
Verwenden Sie diese Fähigkeit beim Erstellen von Funktionen, die Prozessabstürze überstehen, bei Fehlern automatisch wiederholt werden, nach einem Zeitplan ausgeführt werden, auf Ereignisse reagieren oder den Zustand über Infrastrukturausfälle hinweg bewahren müssen – z. B. Webhook-Handler, die Ereignisse verlieren, unzuverlässige Cron-Jobs, Hintergrundjobs, die mitten in der Ausführung fehlschlagen, oder Workflows, die dort weitermachen müssen, wo sie aufgehört haben. Umfasst Inngest-Funktionskonfiguration, Auslöser (Ereignisse, Cron, Aufruf), Schrittausführung und Memoisierung, Idempotenz, Abbruch, Fehlerbehandlung, Wiederholungen, Protokollierung und Beobachtbarkeit.
Einführung in durable Functions
Inngest ist eine Plattform für durable Functions – das sind serverlose Funktionen, die gegen jede Art von Fehler resistent sind und den Zustand über Schritte hinweg speichern. Jede Funktion reagiert auf ein Ereignis, einen Cron-Zeitplan oder einen Aufruf und besteht aus mehreren Schritten. Die Zustände der Schritte werden automatisch im Inngest-System gespeichert, sodass die Ausführung selbst nach einem Neustart des Prozesses präzise dort fortgesetzt werden kann, wo sie aufgehört hat.
Hauptkonzepte
Funktionen definieren
Funktionen werden mit inngest.createFunction() definiert:
import { inngest } from "@/lib/inngest";
export const myFunction = inngest.createFunction(
{ id: "mein-funktion-name" },
{ event: "benutzer/registriert" },
async ({ event, step }) => {
// Ihre Logik hier
}
);
Auslöser
Funktionen können auf verschiedene Weise ausgelöst werden:
- Ereignisse: Wird ausgelöst, wenn ein bestimmtes Ereignis gesendet wird (
{ event: "app/ereignis.art" }). - Cron: Wird nach einem Zeitplan ausgelöst (
{ cron: "0 0 * * *" }). - Aufruf: Wird programmatisch über die Inngest-API ausgelöst (
{ invoke: "meine-funktion" }).
Schrittausführung und Memoisierung
Jeder Schritt in einer Funktion wird mit step.run() definiert. Das System merkt sich den Rückgabewert eines Schritts, sodass bei einer Wiederholung der Schritt nicht erneut ausgeführt wird.
const benutzer = await step.run("benutzer-abrufen", async () => {
const response = await fetch(`https://api.ihreservice.com/benutzer/${event.data.benutzerId}`);
return response.json();
});
const aktualisiert = await step.run("benutzer-aktualisieren", async () => {
// Dieser Schritt verwendet den gemerkten benutzer-Wert
return await updateUser(event.data.benutzerId, { status: "aktiv" });
});
Idempotenz
Stellen Sie Idempotenz mit der Option idempotencyKey sicher:
export const zahlungVerarbeiten = inngest.createFunction(
{
id: "zahlung-verarbeiten",
idempotencyKey: `zahlung-${event.data.transaktionsId}`,
},
{ event: "zahlung/erstellt" },
async ({ event, step }) => {
// Diese Funktion führt nur einmal pro transaktionsId aus
}
);
Wiederholungen und Fehlerbehandlung
Konfigurieren Sie das Wiederholungsverhalten und behandeln Sie Fehler:
export const unzuverlaessigerJob = inngest.createFunction(
{
id: "unzuverlaessiger-job",
retries: { maxAttempts: 5, backoff: "exponential" },
},
{ event: "job/ausfuehren" },
async ({ event, step }) => {
try {
await step.run("riskante-operation", async () => {
// Code, der fehlschlagen könnte
});
} catch (fehler) {
await step.run("fehler-melden", async () => {
// Fehler melden, aber Funktion nicht neu werfen
});
}
}
);
Abbruch
Brechen Sie eine laufende Funktion ab mit:
export const stornierbareBestellung = inngest.createFunction(
{
id: "bestellung-verarbeiten",
cancelOn: [
{
event: "bestellung/storniert",
match: "data.bestellNr",
},
],
},
{ event: "bestellung/erstellt" },
async ({ event, step }) => {
// Diese Funktion wird abgebrochen, wenn ein passendes Storno-Ereignis eintrifft
}
);
Integrationen
Inngest funktioniert nahtlos mit:
- Next.js (App Router und Pages Router)
- Remix
- Express
- Python (FastAPI, Flask, Django)
- TypeScript/JavaScript (jedes Node.js-Framework)
Logging und Beobachtbarkeit
Verwenden Sie step.run() für Logging und integrieren Sie mit gängigen Observability-Tools:
export const datenPipeline = inngest.createFunction(
{ id: "daten-verarbeiten" },
{ cron: "*/5 * * * *" },
async ({ event, step, logger }) => {
logger.info("Datenverarbeitung gestartet");
const daten = await step.run("daten-abrufen", async () => {
// Externe API abfragen
});
logger.info(`Empfangene ${daten.length} Datensätze`);
await step.run("daten-speichern", async () => {
// In Datenbank speichern
});
}
);
Best Practices
- Verwenden Sie aussagekräftige Schrittnamen – sie erscheinen im Dashboard und in Logs.
- Jeder
step.run()-Aufruf muss auf oberster Ebene sein – nicht in if-/try-/for-Blöcke eingeschlossen, sondern immer auf der obersten Ausführungsebene der Funktion. - Halten Sie Schritte klein und atomar – jeder Schritt sollte eine einzelne Operation sein (DB-Schreiben, API-Aufruf).
- Verwenden Sie Idempotenz für zustandsverändernde Operationen – insbesondere bei Zahlungen oder anderen kritischen Aktionen.
- Konfigurieren Sie Wiederholungen mit Bedacht – nutzen Sie exponentielles Backoff für fehleranfällige Operationen.
- Protokollieren Sie wichtige Schritte – hilft beim Debuggen und Überwachen des Systemzustands.