Durable Endpoints
Keep HTTP requests recoverable so callers can receive a response after temporary failures.
Recover an HTTP request after a failure across every client, without changes. A Durable Endpoint adds reliability and recovery to regular APIs, using standard HTTP requests and responses. Inngest saves completed steps and retries failed work. If recovery takes longer, the endpoint can redirect the client to await the final response.
How Durable Endpoints work
- Your client sends a request to your endpoint.
- Your handler runs normal application code. Put operations that need retry and recovery inside
step.run(). - Inngest stores completed step results asynchronously. Your endpoint continues without waiting for storage, so recording results does not slow the API request. If a later step fails, Inngest retries it and reuses completed step results.
- If steps need to retry, the client is redirected to a new URL that waits for the API result.
- When Inngest finishes the retry of the API, the result is sent to the user waiting for the result at its new URL.
This shows the retry path. On a successful first attempt, your endpoint returns the HTTP response directly.
Handling errors or async waits
On the normal success path, the caller receives the response from your route. You can also use step.sleep() and step.waitForEvent() in a Durable Endpoint. This turns the run async, and immediately
redirects the client to a new URL to wait for the run to complete. Inngest records these waits in the run trace.
An example Durable Endpoint
This TypeScript v4 example wraps a Next.js POST handler with inngest.endpoint() and reads a JSON body. Replace the application functions with your own code.
import { Inngest, step } from "inngest";
import { endpointAdapter } from "inngest/next";
import { NextRequest } from "next/server";
const inngest = new Inngest({
id: "orders-app",
endpointAdapter,
});
export const POST = inngest.endpoint(async (req: NextRequest) => {
const { orderId } = (await req.json()) as { orderId?: string };
if (!orderId) {
return Response.json({ error: "orderId is required" }, { status: 400 });
}
const order = await step.run("load-order", () => loadOrder(orderId));
const reservation = await step.run("reserve-inventory", () =>
reserveInventory(order)
);
return Response.json({ orderId, reservation });
});
Send a JSON body such as { "orderId": "123" } to this route. If reserve-inventory fails, Inngest retries that step without rerunning load-order. Make operations with external effects safe to retry, because the step that fails can run again.
Current support and limits
- Durable Endpoints are beta, and are available in TypeScript and Go.
- Workflow flow control such as concurrency and rate limits does not currently apply to Durable Endpoints.
deferandgroup.experimentdon't work in Durable Endpoints. All other primitives do.- Streaming is in developer preview.
Durable endpoints vs durable workflows
- Durable Endpoint: An HTTP request starts the work, and the caller receives its result as an HTTP response. This allows synchronous API requests to survive temporary step errors. Endpoints are for lighter, synchronous functions where the caller needs a response and should last no longer than 60 seconds.
- Durable workflow: An event, schedule, webhook, or another function starts background work. Your API can return after sending an event while the workflow continues. Use it when the caller does not need to wait for the result, or if the workflow takes longer than 60 seconds.