0Pricing
Azure Fundamentals · Leçon

Durable Functions pour les flux de travail avec état

Orchestrez des flux de travail de longue durée avec les modèles d’orchestrateur Durable Functions (distribution-regroupement, chaînage, supervision) et comprenez comment l’état est enregistré par points de contrôle.

Durable Functions pour les flux de travail avec état est une leçon Azure Fundamentals gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Azure Fundamentals, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Azure Fundamentals comprend 4 leçons au total.

Pourquoi utiliser Durable Functions ?

Les fonctions Azure classiques sont sans état : chaque invocation s’exécute indépendamment, sans conserver la mémoire des appels précédents. Durable Functions étend Azure Functions en permettant d’écrire des flux de travail avec état et de longue durée à l’aide d’un simple code async/await. Durable Task Framework enregistre automatiquement des points de contrôle dans Azure Storage après chaque étape. Les flux de travail peuvent ainsi survivre aux redémarrages de serveur, aux délais d’expiration ou aux opérations de maintenance planifiées, puis reprendre exactement là où ils s’étaient arrêtés.

Les trois types de fonctions

Durable Functions introduit trois types de fonctions. Une fonction d’orchestration coordonne l’ensemble du flux de travail : elle appelle les fonctions d’activité et attend les résultats à l’aide de yield ou de await, sans bloquer réellement un thread. Une fonction d’activité effectue une seule unité de travail (appeler une API, écrire dans une base de données) et constitue le seul endroit où des effets de bord doivent se produire. Une fonction d’entité conserve de petites portions d’état durable (compteurs, indicateurs) entre les appels.

// 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);
};

Le modèle d’enchaînement

Le modèle d’enchaînement exécute les fonctions d’activité séquentiellement, en transmettant la sortie de l’une comme entrée de la suivante. L’orchestrateur attend chaque activité à tour de rôle. Si une activité échoue, le flux de travail s’arrête et peut être redémarré à partir de l’étape en échec. Il s’agit du modèle Durable Functions le plus simple, adapté aux flux de travail dans lesquels chaque étape dépend du résultat de la précédente, comme les pipelines de traitement des commandes.

// 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 };
});

Modèle de distribution et de regroupement

Le modèle de distribution et de regroupement lance plusieurs fonctions d’activité en parallèle et attend qu’elles soient toutes terminées avant de poursuivre. L’orchestrateur démarre toutes les tâches simultanément à l’aide de callActivity, sans les attendre, rassemble les objets de tâche dans un tableau, puis effectue l’attente sur Task.all(). Cette approche est beaucoup plus rapide qu’un traitement séquentiel pour les éléments indépendants, comme le traitement de plusieurs fichiers, l’appel de plusieurs API ou les opérations par lots.

// 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;
});

Le modèle de surveillance

Le modèle de surveillance interroge un système externe à intervalles réguliers jusqu’à ce qu’une condition soit remplie : il s’agit d’une boucle d’interrogation, mais entièrement durable. L’orchestrateur appelle une activité pour vérifier l’état, attend un intervalle configurable à l’aide de createTimer, puis recommence. Comme l’état est enregistré dans le stockage entre chaque interrogation, l’orchestrateur ne consomme pas de ressources de calcul pendant l’attente, ce qui le rend bien plus efficace qu’une approche fondée sur une temporisation en veille.

// 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');
});

Modèle d’interaction humaine

Le modèle d’interaction humaine met une orchestration en pause et attend un événement externe, comme l’approbation d’un responsable. L’orchestrateur attend sur waitForExternalEvent, qui peut patienter plusieurs jours ou semaines sans consommer de ressources de calcul. Un système externe (lien d’approbation envoyé par e-mail, application mobile, webhook) appelle l’API HTTP de Durable Functions pour déclencher l’événement et débloquer l’orchestration. Associez cette approche à une temporisation pour gérer automatiquement le délai d’expiration et l’escalade lorsqu’aucune réponse n’arrive.

// 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';
  }
});

Contraintes des orchestrateurs

Les fonctions d’orchestration sont soumises à des contraintes importantes, car elles peuvent être rejouées plusieurs fois à partir de l’historique afin de reconstruire l’état. Elles doivent être déterministes : n’utilisez jamais Date.now() ou Math.random(), et n’effectuez pas directement d’opérations d’E/S. Utilisez plutôt context.df.currentUtcDateTime pour les horodatages et appelez des fonctions d’activité pour toutes les opérations d’E/S. La journalisation dans le corps de l’orchestrateur produit des entrées de journal en double lors de la relecture ; utilisez plutôt des fonctions d’activité pour la journalisation.

// 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
});

Gestion des instances : état et arrêt

Chaque exécution d’orchestration possède un identifiant d’instance unique que vous pouvez utiliser pour interroger son état, envoyer des événements ou l’arrêter. L’API HTTP de gestion de Durable Functions fournit des points de terminaison pour vérifier l’état (GET /instances/{id}), envoyer des événements (POST /instances/{id}/raiseEvent/{name}) et arrêter une instance (POST /instances/{id}/terminate). Utilisez la liaison du client Durable dans vos fonctions pour accéder à ces opérations par programmation.

// 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
    }
  };
};

Stockage et performances

Durable Functions stocke l’historique des orchestrations, l’état des instances et les files de messages entre fonctions dans un compte Azure Storage (ou dans des backends Azure SQL/Netherite pour un débit supérieur). Chaque point de contrôle écrit dans Azure Table Storage et Azure Queue Storage. Pour les scénarios à haut débit (des milliers d’orchestrations simultanées), le backend de stockage Netherite utilise Azure Event Hubs pour offrir des performances nettement supérieures. Surveillez la profondeur de la file d’orchestration afin de détecter les goulots d’étranglement.

// 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'
      }
    }
  }
}

Gestion des erreurs et nouvelles tentatives

Les fonctions d’activité peuvent lever des exceptions, qui sont propagées à l’orchestrateur sous la forme de TaskFailedException. Utilisez des blocs try-catch dans l’orchestrateur pour gérer les échecs correctement. Pour les erreurs transitoires, configurez des nouvelles tentatives automatiques avec temporisation progressive à l’aide de callActivityWithRetry, en indiquant le nombre maximal de tentatives, l’intervalle avant la première nouvelle tentative et le coefficient de temporisation progressive. Il s’agit du modèle recommandé pour les activités qui appellent des API ou des bases de données externes.

// 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;
  }
});

Entités durables

Les entités durables (fonctions d’entité) implémentent de petites portions d’état durable accessibles par identité, à la manière d’acteurs virtuels. Une entité possède un identifiant et un état qui persistent entre les appels. Vous appelez des opérations sur une entité depuis un orchestrateur ou un client, et l’entité les traite une par une (de manière sérialisée). Parmi les utilisations courantes figurent les compteurs, les automates d’état d’approbation, les limiteurs de débit et les paniers d’achat : tout scénario nécessitant un état durable et actualisable sans base de données.

// 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);

Vérification rapide

Testez votre compréhension des concepts de Microsoft Azure Fundamentals (AZ-900) présentés dans cette leçon.

Récapitulatif de la leçon

Dans cette leçon, vous avez appris que Durable Functions permet de créer des flux de travail avec état et de longue durée en enregistrant des points de contrôle de l’état de l’orchestrateur dans Azure Storage, que les principaux modèles sont l’enchaînement, la distribution et le regroupement, la surveillance et l’interaction humaine, et que les orchestrateurs doivent être déterministes : toutes les opérations d’E/S et les appels non déterministes doivent passer par des fonctions d’activité. Nous allons maintenant découvrir Azure Logic Apps.

Questions Fréquemment Posées

La leçon « Durable Functions pour les flux de travail avec état » est-elle gratuite ?

Oui — le texte complet de « Durable Functions pour les flux de travail avec état » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Azure Fundamentals, passe à CoddyKit PRO. Le cours Azure Fundamentals comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Durable Functions pour les flux de travail avec état » ?

Orchestrez des flux de travail de longue durée avec les modèles d’orchestrateur Durable Functions (distribution-regroupement, chaînage, supervision) et comprenez comment l’état est enregistré par poi… Tu pratiques Azure Fundamentals avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Azure Fundamentals ?

Aucune expérience préalable n'est requise. Azure Fundamentals sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Durable Functions pour les flux de travail avec état » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Azure Fundamentals ?

Oui. Chaque leçon Azure Fundamentals inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Déclencheurs et liaisons Azure Functions
  2. Durable Functions pour les flux de travail avec état
  3. Azure Logic Apps
  4. Event Grid et architecture pilotée par les événements
← Retour à Azure Fundamentals