Durable Orchestration¶
This recipe implements a complete Durable Functions Node.js v4 workflow with an HTTP starter, orchestrator, and activity function.
Architecture¶
flowchart LR
START[HTTP Starter] --> CLIENT[Durable Client]
CLIENT --> ORCH[Orchestrator Function]
ORCH --> ACT1[Activity: validateOrder]
ORCH --> ACT2[Activity: reserveInventory]
ORCH --> ACT3[Activity: emitConfirmation] Prerequisites¶
Install durable package:
Use extension bundle v4 in host.json:
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
}
}
Working Node.js v4 Code¶
const { app } = require("@azure/functions");
const df = require("durable-functions");
app.http("startOrderOrchestration", {
methods: ["POST"],
route: "orchestrators/order-processing",
authLevel: "function",
extraInputs: [df.input.durableClient()],
handler: async (request, context) => {
const payload = await request.json();
const client = df.getClient(context);
const instanceId = await client.startNew("orderProcessingOrchestrator", {
input: payload
});
context.log("Started orchestration", { instanceId });
return client.createCheckStatusResponse(request, instanceId);
}
});
df.app.orchestration("orderProcessingOrchestrator", function* (context) {
const input = context.df.getInput();
const validatedOrder = yield context.df.callActivity("validateOrder", input);
const inventory = yield context.df.callActivity("reserveInventory", validatedOrder);
const confirmation = yield context.df.callActivity("emitConfirmation", inventory);
return confirmation;
});
df.app.activity("validateOrder", {
handler: (order) => {
if (!order?.orderId || !order?.customerId) {
throw new Error("orderId and customerId are required.");
}
return { ...order, validatedUtc: new Date().toISOString() };
}
});
df.app.activity("reserveInventory", {
handler: (order) => {
return {
...order,
inventoryReservationId: `${order.orderId}-inv`
};
}
});
df.app.activity("emitConfirmation", {
handler: (order) => {
return {
orderId: order.orderId,
reservationId: order.inventoryReservationId,
status: "Confirmed"
};
}
});
Implementation Notes¶
- Use
df.input.durableClient()+df.getClient(context)in the HTTP starter for orchestration control APIs. - Start orchestrations with the durable client start API (
client.startNew(...), often described asdf.app.client.start()in starter patterns). - Keep orchestrator logic deterministic: no random values, no network calls, no current-time APIs inside orchestrator code.
- Put all external interactions in activities (
df.app.activity(...)).