Azure Fundamentals · Les

Durable Functions voor stateful workflows

Orkestreer langlopende workflows met orchestratorpatronen van Durable Functions (fan-out/fan-in, chaining, monitor) en begrijp hoe de status wordt gecheckpoint.

Les 2 van 413 stappen

Durable Functions voor stateful workflows is een gratis Azure Fundamentals-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Azure Fundamentals. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Azure Fundamentals bevat in totaal 4 lessen.

Waarom Durable Functions?

Normale Azure Functions zijn stateless: elke aanroep wordt onafhankelijk uitgevoerd en heeft geen geheugen van eerdere aanroepen. Durable Functions breiden Azure Functions uit met de mogelijkheid om stateful, langdurige workflows te schrijven met gewone async/await-code. Het Durable Task Framework slaat na elke stap automatisch een checkpoint van de status op in Azure Storage. Daardoor kunnen workflows serverherstarts, time-outs of gepland onderhoud overleven en precies verdergaan waar ze waren gebleven.

De drie functietypen

Durable Functions introduceert drie functietypen. Een orchestratorfunctie coördineert de volledige workflow: deze roept activityfuncties aan en wacht op resultaten met yield of await, zonder daadwerkelijk een thread te blokkeren. Een activityfunctie voert één afzonderlijke werkeenheid uit (een API aanroepen, naar een database schrijven) en is de enige plek waar neveneffecten mogen optreden. Een entityfunctie beheert kleine stukken duurzame status (tellers, vlaggen) tussen aanroepen door.

// Client function (HTTP trigger) — starts the orchestration
module.exports = async function (context, req) {
  const client = df.getClient(context);
  const orderId = req.body.orderId;
  const instanceId = await client.startNew('OrderOrchestrator', undefined, { orderId });
  return client.createCheckStatusResponse(context.bindingData.req, instanceId);
};

Het ketenpatroon

Het ketenpatroon voert activityfuncties opeenvolgend uit en geeft de uitvoer van de ene functie door als invoer voor de volgende. De orchestrator wacht telkens op de volgende activity. Als een activity mislukt, stopt de workflow en kan deze opnieuw worden gestart vanaf de mislukte stap. Dit is het eenvoudigste Durable Functions-patroon en is geschikt voor workflows waarbij elke stap afhankelijk is van het resultaat van de vorige, zoals verwerkingspijplijnen voor bestellingen.

// Orchestrator: chaining pattern
const df = require('durable-functions');
module.exports = df.orchestrator(function* (context) {
  const orderId = context.df.getInput().orderId;

  const validated = yield context.df.callActivity('ValidateOrder', orderId);
  const charged   = yield context.df.callActivity('ChargePayment', validated);
  const shipped   = yield context.df.callActivity('ShipOrder', charged);

  return { status: 'shipped', trackingId: shipped.trackingId };
});

Fan-out-/fan-in-patroon

Het fan-out-/fan-in-patroon start meerdere activityfuncties parallel en wacht tot ze allemaal zijn voltooid voordat het verdergaat. De orchestrator start alle taken gelijktijdig met callActivity, zonder erop te wachten, verzamelt de taakobjecten in een array en voert vervolgens een yield uit op Task.all(). Dit is aanzienlijk sneller dan sequentiële verwerking voor onafhankelijke werkeenheden, zoals het verwerken van meerdere bestanden, het aanroepen van meerdere API's of batchbewerkingen.

// Orchestrator: fan-out / fan-in
module.exports = df.orchestrator(function* (context) {
  const items = context.df.getInput().items;

  // Fan-out: start all tasks in parallel
  const tasks = items.map(item => context.df.callActivity('ProcessItem', item));

  // Fan-in: wait for all tasks to complete
  const results = yield context.df.Task.all(tasks);

  return results;
});

Het monitorpatroon

Het monitorpatroon controleert met vaste tussenpozen een extern systeem totdat aan een voorwaarde is voldaan, vergelijkbaar met een pollinglus maar volledig duurzaam. De orchestrator roept een activity aan om de status te controleren, wacht een configureerbaar interval met createTimer en herhaalt dit vervolgens. Omdat de status tussen elke controle door in de opslag wordt opgeslagen, verbruikt de orchestrator tijdens het wachten geen rekenresources. Dat maakt deze aanpak veel efficiënter dan een aanpak met een slapende timer.

// Orchestrator: monitor pattern (poll until job completes)
module.exports = df.orchestrator(function* (context) {
  const jobId = context.df.getInput().jobId;
  const expiry = new Date(context.df.currentUtcDateTime);
  expiry.setHours(expiry.getHours() + 24); // 24-hour timeout

  while (context.df.currentUtcDateTime < expiry) {
    const status = yield context.df.callActivity('GetJobStatus', jobId);
    if (status === 'completed') return { jobId, status };
    if (status === 'failed') throw new Error('Job failed');
    // Wait 30 seconds before next poll
    const nextCheck = new Date(context.df.currentUtcDateTime);
    nextCheck.setSeconds(nextCheck.getSeconds() + 30);
    yield context.df.createTimer(nextCheck);
  }
  throw new Error('Workflow timed out');
});

Patroon voor menselijke interactie

Het patroon voor menselijke interactie pauzeert een orchestration en wacht op een externe gebeurtenis, zoals goedkeuring door een manager. De orchestrator voert een yield uit op waitForExternalEvent. Dit kan dagen of weken wachten zonder rekenresources te verbruiken. Een extern systeem (een goedkeuringslink in een e-mail, een mobiele app of een webhook) roept de HTTP-API van Durable Functions aan om de gebeurtenis te activeren, waardoor de orchestration verdergaat. Combineer dit met een timer voor automatische time-outs en escalatie als er geen reactie komt.

// Orchestrator: wait for human approval with timeout
module.exports = df.orchestrator(function* (context) {
  const request = context.df.getInput();

  yield context.df.callActivity('SendApprovalEmail', request);

  const timeout = df.Task.createTimer(context, new Date(Date.now() + 48 * 3600 * 1000));
  const approval = context.df.waitForExternalEvent('ApprovalResponse');

  const winner = yield context.df.Task.any([approval, timeout]);

  if (winner === approval) {
    const approved = winner.result;
    return approved ? 'Approved' : 'Rejected';
  } else {
    return 'Timed out — escalated';
  }
});

Beperkingen van orchestrators

Orchestratorfuncties hebben belangrijke beperkingen, omdat ze meerdere keren vanuit de geschiedenis kunnen worden afgespeeld om de status opnieuw op te bouwen. Ze moeten deterministisch zijn: gebruik nooit Date.now() of Math.random() en voer geen directe I/O-aanroepen uit. Gebruik in plaats daarvan context.df.currentUtcDateTime voor tijdstempels en roep activityfuncties aan voor alle I/O. Logging in de body van de orchestrator levert tijdens het afspelen dubbele logregels op; gebruik in plaats daarvan activityfuncties voor logging.

// WRONG — non-deterministic, will cause replay bugs
module.exports = df.orchestrator(function* (context) {
  const now = new Date();          // Don't use Date()
  const rand = Math.random();       // Don't use Math.random()
  const data = await fetch('/api'); // Don't make HTTP calls directly
});

// CORRECT
module.exports = df.orchestrator(function* (context) {
  const now = context.df.currentUtcDateTime; // OK
  const data = yield context.df.callActivity('FetchData', null); // OK
});

Instanties beheren: status en beëindiging

Elke orchestration-uitvoering heeft een unieke instantie-ID die je kunt gebruiken om de status op te vragen, gebeurtenissen te verzenden of de uitvoering te beëindigen. De HTTP-beheer-API van Durable Functions biedt eindpunten voor het controleren van de status (GET /instances/{id}), het verzenden van gebeurtenissen (POST /instances/{id}/raiseEvent/{name}) en het beëindigen van de uitvoering (POST /instances/{id}/terminate). Gebruik de Durable-clientbinding in je functies om deze bewerkingen programmatisch uit te voeren.

// Client function: check orchestration status
module.exports = async function (context, req) {
  const client = df.getClient(context);
  const instanceId = req.params.instanceId;

  const status = await client.getStatus(instanceId, true, true, true);
  return {
    status: 200,
    body: {
      instanceId,
      runtimeStatus: status.runtimeStatus,
      customStatus: status.customStatus,
      output: status.output
    }
  };
};

Opslagbackend en prestaties

Durable Functions slaat de geschiedenis van orchestrations, de status van instanties en berichtenwachtrijen tussen functies op in een Azure Storage Account (of in Azure SQL-/Netherite-backends voor een hogere verwerkingssnelheid). Elk checkpoint schrijft naar Azure Table Storage en Azure Queue Storage. Voor scenario's met een hoge verwerkingssnelheid (duizenden gelijktijdige orchestrations) gebruikt het Netherite-opslagbackend Azure Event Hubs voor aanzienlijk betere prestaties. Houd de diepte van de orchestration-wachtrij in de gaten om knelpunten te detecteren.

// host.json: configure the Durable Task storage provider
{
  'version': '2.0',
  'extensions': {
    'durableTask': {
      'hubName': 'MyTaskHub',
      'storageProvider': {
        'type': 'azure',
        'connectionStringName': 'AzureWebJobsStorage',
        'controlQueueBatchSize': 32,
        'maxQueuePollingInterval': '00:00:02'
      }
    }
  }
}

Foutafhandeling en nieuwe pogingen

Activityfuncties kunnen uitzonderingen genereren, die als TaskFailedException worden doorgegeven aan de orchestrator. Gebruik try-catch-blokken in de orchestrator om fouten zorgvuldig af te handelen. Configureer voor tijdelijke fouten automatische nieuwe pogingen met een oplopende wachttijd via callActivityWithRetry. Geef daarbij het maximale aantal pogingen, het interval voor de eerste nieuwe poging en de coëfficiënt voor de oplopende wachttijd op. Dit is het aanbevolen patroon voor activities die externe API's of databases aanroepen.

// Orchestrator: retry an activity with exponential backoff
module.exports = df.orchestrator(function* (context) {
  const retryOptions = new df.RetryOptions(
    5000,  // firstRetryIntervalInMilliseconds
    3      // maxNumberOfAttempts
  );
  retryOptions.backoffCoefficient = 2; // 5s, 10s, 20s

  try {
    const result = yield context.df.callActivityWithRetry(
      'CallExternalAPI',
      retryOptions,
      context.df.getInput()
    );
    return result;
  } catch (e) {
    yield context.df.callActivity('SendFailureAlert', e.message);
    throw e;
  }
});

Durable Entities

Durable Entities (entityfuncties) implementeren kleine stukken duurzame status die op basis van een identiteit toegankelijk zijn, vergelijkbaar met virtuele actors. Een entity heeft een ID en een status die tussen aanroepen door behouden blijft. Je roept bewerkingen op een entity aan vanuit een orchestrator of client, waarna de entity deze één voor één verwerkt (geserialiseerd). Veelgebruikte toepassingen zijn tellers, goedkeuringsstatusmachines, snelheidsbegrenzers en winkelwagens: elk scenario waarin duurzame, bijwerkbare status nodig is zonder database.

// Counter entity function
const df = require('durable-functions');
module.exports = df.entity(function (context) {
  let count = context.df.getState(() => 0);
  const operation = context.df.operationName;

  if (operation === 'add') count += context.df.getInput();
  if (operation === 'reset') count = 0;
  if (operation === 'get') context.df.return(count);

  context.df.setState(count);
});

// From orchestrator, increment counter entity
// const entityId = new df.EntityId('Counter', 'myCounter');
// yield context.df.callEntity(entityId, 'add', 1);

Korte kennistest

Test je begrip van de concepten uit Microsoft Azure Fundamentals (AZ-900) uit deze les.

Samenvatting van de les

In deze les heb je geleerd dat Durable Functions stateful, langdurige workflows mogelijk maken door de status van de orchestrator op te slaan in Azure Storage, dat belangrijke patronen ketenen, fan-out/fan-in, monitoren en menselijke interactie omvatten en dat orchestrators deterministisch moeten zijn: alle I/O en niet-deterministische aanroepen moeten via activityfuncties verlopen. Hierna bekijken we Azure Logic Apps.

Gratis beginnen

Leer Azure Fundamentals met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
30
Lessen
120

Veelgestelde vragen

Is de les “Durable Functions voor stateful workflows” gratis?

Ja — de volledige tekst van “Durable Functions voor stateful workflows” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Azure Fundamentals wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Azure Fundamentals bevat in totaal 4 lessen.

Wat leer ik in “Durable Functions voor stateful workflows”?

Orkestreer langlopende workflows met orchestratorpatronen van Durable Functions (fan-out/fan-in, chaining, monitor) en begrijp hoe de status wordt gecheckpoint. Je oefent met Azure Fundamentals door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met Azure Fundamentals te beginnen?

Ervaring vooraf is niet nodig. Azure Fundamentals op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.

Hoe lang duurt de les “Durable Functions voor stateful workflows”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over Azure Fundamentals?

Ja. Elke les over Azure Fundamentals bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Triggers en bindings van Azure Functions
  2. Durable Functions voor stateful workflows
  3. Azure Logic Apps
  4. Event Grid en eventgedreven architectuur
← Terug naar Azure Fundamentals