Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Le contrôle de version d’orchestration répond au principal défi du déploiement des modifications apportées aux fonctions d’orchestrateur tout en conservant le modèle d’exécution déterministe requis par Durable Functions. Sans cette fonctionnalité, les changements cassants apportés à la logique d’orchestrateur ou aux signatures de fonction d’activité entraînent l’échec des instances d’orchestration en version d’évaluation, car elles interrompent l’exigence de déterminisme qui assurer l’exécution fiable de l’orchestration. Cette fonctionnalité intégrée fournit une isolation automatique des versions avec une configuration minimale. Il est indépendant du back-end, de sorte qu’il peut être utilisé par des applications tirant parti de n’importe quel fournisseur de stockage de la fonction durable, y compris le planificateur de tâches durables.
Note
Pour les utilisateurs du Planificateur de tâches durables, si vous utilisez les SDK de tâches durables au lieu des fonctions durables, consultez l'article sur la version des SDK de tâches durables.
Terminology
Cet article utilise deux termes connexes mais distincts :
- Fonction Orchestrator (ou simplement « orchestrateur ») : fait référence au code de fonction qui définit la logique de flux de travail , le modèle ou le blueprint pour la façon dont un flux de travail doit s’exécuter.
- Instance d’orchestration (ou simplement « orchestration ») : fait référence à une exécution spécifique d’une fonction d’orchestrateur, avec son propre état, son ID d’instance et ses entrées. Plusieurs instances d’orchestration peuvent s’exécuter simultanément à partir de la même fonction d’orchestrateur.
La compréhension de cette distinction est essentielle pour le contrôle de version d’orchestration, où le code de fonction d’orchestrateur contient une logique prenant en charge la version, tandis que les instances d’orchestration sont définitivement associées à une version spécifique lors de la création.
Fonctionnement
La fonctionnalité de contrôle de version d’orchestration fonctionne sur ces principes fondamentaux :
Association de versions : lorsqu’une instance d’orchestration est créée, elle obtient une version associée définitivement à celle-ci.
Exécution prenant en charge la version : le code de fonction Orchestrator peut examiner la valeur de version associée à l’instance d’orchestration actuelle et à l’exécution de branche en conséquence.
Compatibilité descendante : les workers exécutant des versions d’orchestrateur plus récentes peuvent continuer à exécuter des instances d’orchestration créées par des versions d’orchestrateur plus anciennes.
Protection avancée : le runtime empêche automatiquement les workers exécutant des versions d’orchestrateur plus anciennes d’exécuter des orchestrations démarrées par des versions plus récentes d’orchestrateur.
Important
Le contrôle de version d’orchestration est actuellement en préversion publique.
Prerequisites
Avant d’utiliser le contrôle de version d’orchestration, vérifiez que vous disposez des versions de package requises pour votre langage de programmation.
Si vous utilisez un langage non-.NET (JavaScript, Python, PowerShell ou Java) avec des bundles d’extensions, votre application de fonction doit référencer le bundle d’extensions version 4.26.0 ou ultérieure. Configurez la extensionBundle plage host.json afin que la version minimale soit au moins 4.26.0, par exemple :
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.26.0, 5.0.0)"
}
}
Consultez la documentation de configuration du bundle d’extensions pour plus d’informations sur le choix et la mise à jour des versions de bundle.
Utilisez Microsoft.Azure.Functions.Worker.Extensions.DurableTask la version 1.5.0 ou ultérieure.
Utilisation de base
Le cas d’utilisation le plus courant pour le contrôle de version d’orchestration est le moment où vous devez apporter des changements cassants à votre logique d’orchestrateur tout en conservant les instances d’orchestration en version d’évaluation existantes avec leur version d’origine. Il vous suffit de mettre à jour le defaultVersion dans votre host.json et de modifier votre code orchestrateur pour vérifier la version de l'orchestration et adapter l'exécution des branches en conséquence. Passons en revue les étapes requises.
Note
Le comportement décrit dans cette section cible les situations les plus courantes, et c’est ce que fournit la configuration par défaut. Toutefois, elle peut être modifiée si nécessaire (consultez Utilisation avancée pour plus d’informations ).
Étape 1 : configuration de la version par défaut
Pour configurer la version par défaut de vos orchestrations, vous devez ajouter ou mettre à jour le defaultVersion paramètre dans le host.json fichier dans votre projet Azure Functions :
{
"extensions": {
"durableTask": {
"defaultVersion": "<version>"
}
}
}
La chaîne de version peut suivre n’importe quel format adapté à votre stratégie de contrôle de version :
- Versionnage en plusieurs parties :
"1.0.0","2.1.0" - Numérotation simple :
"1","2" - Basé sur des dates :
"2025-01-01" - Format personnalisé :
"v1.0-release"
Une fois que vous avez défini, defaultVersiontoutes les nouvelles instances d’orchestration seront définitivement associées à cette version.
Règles de comparaison de versions
Lorsque la stratégie Strict ou CurrentOrOlder est sélectionnée (voir Mise en correspondance de version), le runtime compare la version de l’instance d’orchestration à la valeur defaultVersion du Worker en utilisant les règles suivantes :
- Les versions vides ou null sont traitées comme égales.
- Une version vide ou null est considérée comme antérieure à n’importe quelle version définie.
- Si les deux versions peuvent être analysées comme
System.Version, laCompareTométhode est utilisée. - Sinon, une comparaison de chaînes ne respectant pas la casse est effectuée.
Étape 2 : Logique de fonction orchestrateur
Pour implémenter la logique prenant en charge la version dans votre fonction d’orchestrateur, vous pouvez utiliser le paramètre de contexte transmis à l’orchestrateur pour accéder à la version actuelle de l’instance d’orchestration, ce qui vous permet de brancher votre logique d’orchestrateur en fonction de la version.
Important
Lors de l’implémentation d’une logique prenant en charge la version, il est essentiel de conserver la logique d’orchestrateur exacte pour les versions antérieures. Les modifications apportées à la séquence, à l’ordre ou à la signature des appels d’activité pour les versions existantes peuvent interrompre la relecture déterministe et entraîner l’échec des orchestrations en version d’évaluation ou la génération de résultats incorrects. Les anciens chemins de code de version doivent rester inchangés une fois déployés.
[Function("MyOrchestrator")]
public static async Task<string> RunOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
if (context.Version == "1.0")
{
// Original logic for version 1.0
...
}
else if (context.Version == "2.0")
{
// New logic for version 2.0
...
}
...
}
Note
La context.Version propriété est en lecture seule et reflète la version associée définitivement à l’instance d’orchestration lors de sa création. Vous ne pouvez pas modifier cette valeur pendant l’exécution de l’orchestration. Si vous souhaitez spécifier une version par le biais de moyens autres que host.json, vous pouvez le faire lors du démarrage d’une instance d’orchestration avec les API clientes d’orchestration (voir Démarrage de nouvelles orchestrations et sous-orchestrations avec des versions spécifiques).
Tip
Si vous commencez simplement à utiliser le contrôle de version d’orchestration et que vous avez déjà des orchestrations en version d’évaluation créées avant de spécifier un defaultVersion, vous pouvez toujours ajouter le paramètre defaultVersion à votre host.json maintenant. Pour toutes les orchestrations créées précédemment, context.Version retourne null (ou une valeur dépendante du langage équivalente), vous pouvez donc structurer votre logique d’orchestrateur pour gérer les orchestrations héritées (version null) et les nouvelles orchestrations avec version en conséquence. Voici les valeurs dépendantes du langage à vérifier pour le cas hérité :
- C# :
context.Version == nulloucontext.Version is null - JavaScript :
context.df.version == null - Python :
context.version is None - PowerShell :
$null -eq $Context.Version - Java :
context.getVersion() == nullnotez également que la spécification"defaultVersion": nulldanshost.jsonest équivalente à ne pas la spécifier du tout.
Tip
Selon votre situation, vous pouvez préférer le branching à des niveaux différents. Vous pouvez apporter une modification locale précisément là où cette modification est requise, comme l’illustre l’exemple. Vous pouvez également créer une branche à un niveau supérieur, même au niveau de l’implémentation de l’orchestrateur entier, ce qui introduit une duplication de code, mais peut conserver le flux d’exécution clair. C’est à vous de choisir l’approche qui convient le mieux à votre scénario et à votre style de codage.
Que se passe-t-il après le déploiement
Voici ce que vous devez attendre une fois que vous avez déployé votre fonction d’orchestrateur mise à jour avec la nouvelle logique de version :
Coexistence de Workers : les workers contenant le nouveau code de fonction d’orchestrateur démarrent, tandis que certains Workers avec l’ancien code sont potentiellement actifs.
Attribution de version pour les nouvelles instances : toutes les nouvelles orchestrations et sous-orchestrations créées par les nouveaux Workers obtiennent la version à partir du
defaultVersionqui leur est affecté.Compatibilité du nouveau Worker : les nouveaux Workers pourront traiter les orchestrations nouvellement créées et les orchestrations existantes, car les changements effectués à l’Étape 2 de la section précédente assurent la compatibilité descendante via la logique de branchement prenant en charge la version.
Restrictions des anciens travailleurs : les anciens travailleurs sont autorisés à traiter uniquement les orchestrations avec une version égale ou inférieure à la version spécifiée dans leur propre
defaultVersiondanshost.json, car ils ne sont pas censés avoir de code d’orchestrateur compatible avec les versions plus récentes. Cette restriction empêche les erreurs d’exécution et le comportement inattendu.
Note
Le contrôle de version d’orchestration n’influence pas le cycle de vie des Workers. La plateforme Azure Functions gère l’approvisionnement et la désaffectation des workers selon des règles régulières qui varient en fonction des options d’hébergement.
Exemple : remplacement d’une activité dans la séquence
Cet exemple montre comment remplacer une activité par une activité différente au milieu d’une séquence à l’aide du versionnage d’orchestration.
Version 1.0
configuration dans host.json :
{
"extensions": {
"durableTask": {
"defaultVersion": "1.0"
}
}
}
Fonction Orchestrator :
[Function("ProcessOrderOrchestrator")]
public static async Task<string> ProcessOrder(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
var orderId = context.GetInput<string>();
await context.CallActivityAsync("ValidateOrder", orderId);
await context.CallActivityAsync("ProcessPayment", orderId);
await context.CallActivityAsync("ShipOrder", orderId);
return "Order processed successfully";
}
Version 2.0 avec traitement de remise
configuration dans host.json :
{
"extensions": {
"durableTask": {
"defaultVersion": "2.0"
}
}
}
Fonction Orchestrator :
using DurableTask.Core.Settings;
[Function("ProcessOrderOrchestrator")]
public static async Task<string> ProcessOrder(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
var orderId = context.GetInput<string>();
await context.CallActivityAsync("ValidateOrder", orderId);
if (VersioningSettings.CompareVersions(context.Version, "1.0") <= 0)
{
// Preserve original logic for existing instances
await context.CallActivityAsync("ProcessPayment", orderId);
}
else // a higher version (including 2.0)
{
// New logic with discount processing (replaces payment processing)
await context.CallActivityAsync("ApplyDiscount", orderId);
await context.CallActivityAsync("ProcessPaymentWithDiscount", orderId);
}
await context.CallActivityAsync("ShipOrder", orderId);
return "Order processed successfully";
}
Utilisation avancée
Pour les scénarios de gestion de version plus sophistiqués, vous pouvez configurer d’autres paramètres pour contrôler la façon dont le runtime gère les correspondances de version et les incompatibilités.
Tip
Utilisez la configuration par défaut (CurrentOrOlder avec Reject) pour la plupart des scénarios afin d'activer des déploiements progressifs sécurisés tout en préservant l'état d'orchestration pendant les transitions de version. Nous vous recommandons de continuer avec la configuration avancée uniquement si vous avez des exigences spécifiques qui ne peuvent pas être remplies avec le comportement par défaut.
Mise en correspondance des versions
Le versionMatchStrategy paramètre détermine la façon dont le runtime correspond aux versions d’orchestration lors du chargement des fonctions d’orchestrateur. Il contrôle les instances d’orchestration qu'un travailleur peut traiter en fonction de la compatibilité des versions.
Configuration
{
"extensions": {
"durableTask": {
"defaultVersion": "<version>",
"versionMatchStrategy": "CurrentOrOlder"
}
}
}
Stratégies disponibles
None(non recommandé) : ignorez complètement la version d’orchestration. Tout le travail reçu est traité indépendamment de la version. Cette stratégie désactive efficacement la vérification des versions et permet à tout worker de traiter n’importe quelle instance d’orchestration.Strict: traitez uniquement les tâches à partir d’orchestrations avec la même version que celle spécifiée pardefaultVersiondans lehost.jsondu Worker. Cette stratégie fournit le niveau d’isolation de version le plus élevé, mais nécessite une coordination minutieuse du déploiement pour éviter les orchestrations orphelines. Les conséquences de l’incompatibilité de version sont décrites dans la section Gestion des incompatibilités de version .CurrentOrOlder(valeur par défaut) : traitez les tâches à partir d’orchestrations dont la version est inférieure ou égale à la version spécifiée pardefaultVersiondans lehost.jsondu Worker. Cette stratégie permet la compatibilité descendante, ce qui permet aux nouveaux workers de gérer les orchestrations démarrées par des versions d’orchestrateur plus anciennes tout en empêchant les anciens workers de traiter des orchestrations plus récentes. Les conséquences de l’incompatibilité de version sont décrites dans la section Gestion des incompatibilités de version .
Gestion des incompatibilités de version
Le versionFailureStrategy paramètre détermine ce qui se passe lorsqu’une version d’instance d’orchestration ne correspond pas à la version actuelle defaultVersion.
Configuration:
{
"extensions": {
"durableTask": {
"defaultVersion": "<version>",
"versionFailureStrategy": "Reject"
}
}
}
Stratégies disponibles :
Reject(par défaut) : n'exécutez pas l’orchestration. L’instance d’orchestration reste dans son état actuel et peut être réessayée ultérieurement lorsqu’un agent compatible devient disponible. Cette stratégie est l’option la plus sûre, car elle conserve l’état d’orchestration.Fail: échec de l’orchestration. Cette stratégie met immédiatement fin à l’instance d’orchestration avec un état d’échec, qui peut être approprié dans les scénarios où les incompatibilités de version indiquent des problèmes de déploiement graves.
Démarrer des nouvelles orchestrations et sous-orchestrations avec des versions spécifiques
Par défaut, toutes les nouvelles instances d’orchestration sont créées avec le paramètre actuel defaultVersion spécifié dans votre host.json configuration. Toutefois, vous pouvez avoir des scénarios où vous devez créer des orchestrations avec une version spécifique, même s’il diffère de la valeur par défaut actuelle.
Quand utiliser des versions spécifiques :
- Migration progressive : vous souhaitez continuer à créer des orchestrations avec une version antérieure, même après le déploiement d’une version plus récente.
- Scénarios de test : vous devez tester un comportement de version spécifique en production.
- Situations de restauration : vous devez rétablir temporairement la création d’instances avec une version précédente.
- Flux de travail spécifiques aux versions : différents processus métier nécessitent différentes versions d’orchestration.
Vous pouvez remplacer la version par défaut en fournissant une valeur de version spécifique lors de la création de nouvelles instances d’orchestration à l’aide des API clientes d’orchestration. Cela permet un contrôle précis sur la version utilisée par chaque nouvelle instance d’orchestration.
[Function("HttpStart")]
public static async Task<HttpResponseData> HttpStart(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
[DurableClient] DurableTaskClient client,
FunctionContext executionContext)
{
var options = new StartOrchestrationOptions
{
Version = "1.0"
};
string instanceId = await client.ScheduleNewOrchestrationInstanceAsync("ProcessOrderOrchestrator", orderId, options);
// ...
}
Vous pouvez également démarrer des sous-orchestrations avec des versions spécifiques à partir d’une fonction d’orchestrateur :
[Function("MainOrchestrator")]
public static async Task<string> RunMainOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
var subOptions = new SubOrchestratorOptions
{
Version = "1.0"
};
var result = await context.CallSubOrchestratorAsync<string>("ProcessPaymentOrchestrator", orderId, subOptions);
// ...
}
Suppression des chemins de code hérités
Au fil du temps, vous pouvez supprimer les chemins de code hérités de vos fonctions d’orchestrateur pour simplifier la maintenance et réduire la dette technique. Toutefois, la suppression du code doit être effectuée avec soin pour éviter d’interrompre les instances d’orchestration existantes.
Quand il est sûr de supprimer le code hérité :
- Toutes les instances d’orchestration utilisant l’ancienne version ont été terminées (réussite, échec ou arrêt)
- Aucune nouvelle instance d’orchestration ne sera créée avec l’ancienne version
- Vous avez vérifié via le monitoring ou l’interrogation qu’aucune instance n’est en cours d’exécution avec la version héritée
- Une période suffisante s’est écoulée depuis le dernier déploiement de l’ancienne version (compte tenu de vos besoins en matière de continuité d’activité)
Bonnes pratiques pour la suppression :
- Surveillez activement les instances en cours d’exécution : utilisez les API de gestion Durable Functions pour rechercher des instances à l’aide de versions spécifiques.
- Définir des stratégies de rétention : définissez la durée pendant laquelle vous envisagez de maintenir la compatibilité descendante pour chaque version.
- Supprimez incrémentiellement : envisagez de supprimer une version à la fois plutôt que plusieurs versions simultanément.
- Suppression de documents : conservez les enregistrements clairs du moment où les versions ont été supprimées et pourquoi.
Warning
La suppression des chemins de code hérités alors que les instances d’orchestration exécutent encore ces versions peut provoquer des échecs de reprises déterministes ou un comportement inattendu. Vérifiez toujours qu’aucune instance n’utilise la version héritée avant de supprimer le code.
Meilleures pratiques
Gestion des versions
-
Utilisez le contrôle de version en plusieurs parties : adoptez un schéma de contrôle de version cohérent comme
major.minor.patch. - Changements cassants de documents : documentez clairement les changements qui nécessitent une nouvelle version.
- Planifier le cycle de vie des versions : définissez quand supprimer les chemins de code hérités.
Organisation du code
- Logique de version distincte : utilisez une branche claire ou des méthodes distinctes pour différentes versions.
- Conserver le déterminisme : évitez de modifier la logique de version existante une fois déployée. Si les modifications sont absolument nécessaires (comme les correctifs de bogues critiques), assurez-vous qu’elles conservent un comportement déterministe et ne modifient pas la séquence d’opérations, ou attendez-vous que les versions d’orchestrateur plus récentes échouent lors du traitement des orchestrations plus anciennes.
- Testez soigneusement : testez tous les chemins de version, en particulier pendant les transitions.
Surveillance et observabilité
- Informations sur la version du journal : incluez la version dans votre journalisation pour faciliter le débogage.
- Surveiller la distribution des versions : effectuez le suivi des versions qui s’exécutent activement.
- Configurer des alertes : surveillez les erreurs liées à la version.
Troubleshooting
Problèmes courants
Problème : les instances d’orchestration créées avec la version 1.0 échouent après le déploiement de la version 2.0
- Solution : Vérifiez que le chemin du code version 1.0 dans votre orchestrateur reste exactement le même. Tous les changement apportés à la séquence d’exécution peuvent interrompre la relecture déterministe.
Problème : les workers exécutant des versions d’orchestrateur plus anciennes ne peuvent pas exécuter de nouvelles orchestrations
-
Solution : il s’agit du comportement attendu. Le runtime empêche intentionnellement les anciens Workers d’exécuter des orchestrations avec des versions plus récentes afin de maintenir la sécurité. Vérifiez que tous les agents sont mis à jour vers la dernière version de l’orchestrateur et que leur paramètre
defaultVersiondanshost.jsonest mis à jour en conséquence. Vous pouvez modifier ce comportement si nécessaire à l’aide des options de configuration avancées (voir Utilisation avancée pour plus d’informations ).
-
Solution : il s’agit du comportement attendu. Le runtime empêche intentionnellement les anciens Workers d’exécuter des orchestrations avec des versions plus récentes afin de maintenir la sécurité. Vérifiez que tous les agents sont mis à jour vers la dernière version de l’orchestrateur et que leur paramètre
Problème : les informations de version ne sont pas disponibles dans l’orchestrateur (
context.Versionoucontext.getVersion()ont la valeur Null, quel que soit ledefaultVersionparamètre)- Solution : consultez la section Conditions préalables pour vous assurer que votre environnement répond à toutes les conditions requises pour le contrôle de version d’orchestration.
Problème : les orchestrations d’une version plus récente progressent très lentement ou sont complètement bloquées
-
Solution : Le problème peut avoir des causes racines différentes :
-
Workers plus récents insuffisants : assurez-vous qu’un nombre suffisant de Workers contenant une version égale ou ultérieure dans
defaultVersionsont déployés et actifs pour gérer les orchestrations plus récentes. - Interférences de routage d’orchestration des Workers plus anciens : les anciens Workers peuvent interférer avec le mécanisme de routage de l’orchestration, ce qui rend plus difficile pour les nouveaux Workers de récupérer des orchestrations pour le traitement. Cela peut être particulièrement visible lors de l’utilisation de certains fournisseurs de stockage (Stockage Azure ou MSSQL). Normalement, la plateforme Azure Functions garantit que les anciens travailleurs sont supprimés peu après un déploiement, de sorte que tout délai n’est généralement pas significatif. Toutefois, si vous utilisez une configuration qui vous permet de contrôler le cycle de vie des travailleurs âgés, assurez-vous que les travailleurs âgés sont finalement arrêtés. Vous pouvez également envisager d’utiliser le planificateur de tâches durables, car il fournit un mécanisme de routage amélioré qui est moins susceptible de ce problème.
-
Workers plus récents insuffisants : assurez-vous qu’un nombre suffisant de Workers contenant une version égale ou ultérieure dans
-
Solution : Le problème peut avoir des causes racines différentes :