Pourquoi migrer votre Azure Function vers le modèle Isolated worker et vers .NET 8 ?
Comment fonctionne le modèle In-Process
Le modèle In-Process exécute les fonctions Azure directement dans le même processus que le runtime Azure Function. Cela permet de bénéficier de la performance de l’exécution du runtime. Cependant, les fonctions dépendent directement de la version .NET supportée par la plateforme Azure, ce qui limite la flexibilité des développeurs dans le choix des versions.
Pourquoi migrer vers le modèle Isolated worker ?
Avantages du modèle Isolated worker : Le modèle Isolated worker permet l’exécution des fonctions Azure dans un processus isolé, indépendant du runtime d’Azure Functions, permettant aux développeurs de choisir indépendamment la version du framework .NET, y compris des versions plus récentes non encore supportées en In-Process, ce qui offre plusieurs avantages :
- La possibilité d’utiliser des versions plus récentes du .NET, indépendamment de celles supportées par le runtime Azure Functions
- Le code des fonctions est exécuté dans un processus séparé, isolant les dépendances et réduisant les conflits potentiels des dépendances utilisées par la fonction.
- Un meilleur contrôle du pipeline de démarrage de l’application, de la configuration des middlewares et du mécanisme de l’injection des dépendances.
Fin de support pour le modèle In-Process : La date de fin de support pour le modèle In-Process est fixée au 10 novembre 2026. Après cette date, Microsoft ne fournira plus de support ni de maintenance pour ce modèle. Il est donc recommandé de planifier une migration vers le modèle Isolated worker avant cette échéance pour bénéficier du support continu et des nouvelles fonctionnalités.
Migrer vos Azure Functions vers .NET 8
Migrer les fonctions Azure vers .NET 8 peut offrir plusieurs avantages de la nouvelle version. Voici quelques bonnes raisons de procéder à cette migration :
- Performance optimisée : .NET 8 introduit des optimisations dans le runtime, réduisant l’utilisation des ressources et améliorant la rapidité d’exécution des applications.
- Amélioration de la sécurité : Les mises à jour de .NET incluent souvent des correctifs de sécurité et des améliorations, garantissant que votre application reste protégée contre les dernières vulnérabilités.
- Support à long terme (LTS) : .NET 8 bénéficie d’un support à long terme, garantissant des mises à jour de sécurité et de maintenance jusqu’en 2027.
- Nouvelles fonctionnalités de C# 12 : Plus de flexibilité avec les types, simplification de la syntaxe pour une meilleure productivité des développeurs…,
- Écosystème et Communauté : En restant à jour avec les versions récentes de .NET, vous bénéficiez d’une communauté active, ce qui facilite l’accès à des ressources et des solutions aux problèmes que vous pourriez rencontrer.
Défis potentiels de la migration vers le modèle Isolated Worker
La migration n’est pas toujours sans difficultés. Voici quelques défis à anticiper :
- Compatibilité des packages NuGet : Certains packages conçus pour le modèle In-Process peuvent ne pas fonctionner dans le modèle Isolated worker.
- Refactorisation du code : Certaines parties du code devront être réécrites pour s’adapter au modèle Isolated worker, notamment en ce qui concerne les middlewares et les dépendances.
- Changement de comportement : Certains comportements peuvent changer, nécessitant des ajustements dans la logique des fonctions.
Comment migrer une Azure Function de In-process à Isolated worker et vers .NET 8 ?
Migrer des fonctions Azure du modèle In-Process vers le modèle Isolated Worker nécessite plusieurs ajustements dans la configuration et le code. Voici les étapes principales :
1. Vérifier la compatibilité de vos packages
Assurez-vous que toutes les bibliothèques et packages NuGet utilisés dans vos projets sont compatibles avec .NET 8. Pour ce faire, vous pouvez lire la documentation de vos packages nuget dans Nuget Package Manager de votre Visual Studio ou directement sur le site officiel nuget.org.
2. Installation du SDK .NET 8
Vous pouvez télécharger le SDK .NET 8 depuis le site officiel du .NET.
3. Mise à jour du fichier du projet
Cette étape consiste à modifier le fichier du projet (.csproj) pour cibler le modèle Isolated worker et la version .NET 8.
Dans le fichier .csproj, il est important de :
- Remplacez net6.0 par net8.0 dans la propriété TargetFramework, pour spécifier la nouvelle version du framework.
- Mettre à jour la version de la propriété AzureFunctionsVersion pour v4 si ce n’est pas déjà fait.
- Ajouter la propriété <OutputType>Exe</OutputType> propre au modèle Isolated worker. Cette propriété indique que l’application est un exécutable et que la fonction sera exécutée sur un process isolé.
- Ajouter la propriété <ImplicitUsings>enable</ImplicitUsings>: cette propriété est optionnelle mais elle permet d’activer l’importation automatique des espaces de noms courants dans la classe de démarrage.
- Supprimer les références liées au modèle In-Process (commençant par Microsoft.Azure.WebJobs.*) et les remplacer par celles du modèle Isolated worker (commençant par Microsoft.Azure.Function.Worker.*).
Voici un exemple de fichier .csproj avant et après la mise à jour :
Modèle In-Process
Modèle Isolated worker
Configuration du fichier de démarrage
Avec le modèle Isolated-worker, le fichier de démarrage Startup.cs devient Program.cs. Il faut transférer la configuration de votre application vers le nouveau fichier de démarrage en effectuant quelques ajustements
Modèle In-Process
Modèle Isolated worker
Mise à jour du code pour le modèle Isolated worker
Dans le modèle Isolated worker, il est nécessaire de faire des ajustements au niveau du code (notamment les classes de Binding et des Triggers) afin de l’adapter au contexte du modèle Isolated worker : nom de certaines classes, Interfaces, …
Voici quelques exemples de changement de classes/méthodes :
Ci-dessous un exemple de mise à jour d’une fonction :
Modèle In-Process
Modèle Isolated worker
Mettre à jour le runtime pour Isolated worker :
Pour que la fonction Azure s’exécute avec le modèle Isolated worket, il est nécessaire de définir la variable FUNCTIONS_WORKER_RUNTIME à dotnet-isolated au lieu de dotnet, dans le fichier local.settings.json
Tester et corriger les éventuelles incompatibilités
Avant de déployer votre application Azure Functions, il est important de tester les fonctions en local. Cette étape est cruciale car certains changements de comportements provoquant des erreurs runtime ne peuvent être détectés qu’au moment de l’exécution.
Mettre à jour les configurations de vos ressources dans Azure
Une fois que votre application Azure Function fonctionne correctement en local, il est temps de la déployer sur Azure. Assurez-vous de mettre à jour la variable d’environnement FUNCTIONS_WORKER_RUNTIME pour qu’elle soit définie sur dotnet-isolated au lieu de dotnet. Cette variable indique le modèle utilisé par votre application, qui est dans ce cas le modèle Isolated Worker.
Pensez à mettre à jour la version de .NET si cela n’a pas été fait automatiquement lors du déploiement
Quelques retours d’expériences et pièges à éviter :
Mise à jour des classes liées à l’exécution des fonctions :
Si vous utilisez la classe HttpRequest dans votre fonction en mode In-process, il faut la remplacer par HttpRequestData lors du passage au mode Isolated Worker. En effet, bien que la compilation puisse réussir en conservant HttpRequest, des erreurs surviendront à l’exécution.
Le même principe s’applique à la classe HttpRequestMessage, qui devient HttpRequest dans le modèle Isolated Worker.
Pour plus de détails, vous pouvez consulter la table de comparaison sur Microsoft Learn via ce lien.
In-Process
Isolated
Problème avec ActivityTrigger et BlobInput : le nom de BlobClient est toujours récupéré entre deux quottes. Cela empêche la récupération des propriétés blobClient.GetProperties.
Pour contourner ce problème, vous pouvez récupérer « manuellement » le BlobClient en utilisant son nom qui est passé en paramètre dans la méthode de l’Activity :
Utilisation du logger : Avec le modèle Isolated, on ne peut plus récupérer le logger (ILogger) directement dans les paramètres de la fonction :
Cependant, vous pouvez utiliser la nouvelle instance FunctionContext pour récupérer votre logger ILogger (cf capture ci-dessous).
Sérialisation/Désérialisation des objets composés : Un problème de sérialisation/désérialisation se manifeste lors de l’appel à CallActivityAsync pour récupérer un objet composé.
Dans cet exemple, nous récupérons une liste « Items » vide, alors que l’activity « ImportFileFunction » renvoie bien une liste « Items » contenant un élément avec une liste Data de 40 éléments.
Ce problème peut être lié au changement de sérialiseur suite à la migration vers le modèle Isolated worker. En effet, le modèle Isolated worker utilise par défaut la bibliothèque de sérialisation JSON System.Text.Json, alors que le modèle In-Process utilise Newtonsoft.Json.
Pour contourner ce problème, on peut effectuer la sérialisation explicitement dans le code de vos fonctions :
Une autre solution possible qui consiste à configurer le modèle Isolated worker à utiliser la bibliothèque Newtonsoft.Json de cette manière :
- Créer une méthode d’extension sur IFunctionsWorkerApplicationBuilder pour permettre à votre application d’utiliser le sérialiseur Newtonsoft.Json.
- Dans le fichier de démarrage Progam.cs , appeler la méthode d’extension précédemment créée lors de la configuration de votre application. Cela force le modèle Isolated worker à utiliser la bibliothèque Newtonsoft.Json pour les opérations de sérialisation et désérialisation.
Mise à jour de packages NuGet soumis à une licence : Certains packages soumis à une licence nécessitent un renouvellement de la licence en cas de mise à jour de version. Il est recommandé de ne pas mettre à jour ces packages si vous ne souhaitez pas renouveler votre licence pour éviter des frais supplémentaires qui ne sont pas vraiment nécessaires. Exemple : le package NuGet Syncfusion https://www.nuget.org/packages/Syncfusion.Licensing .
Déploiement CI/CI via GitHub Actions : Depuis début septembre 2024, le package upload-artifact de GitHub Actions a été mis à jour et n’inclut plus par défaut les dossiers cachés. Cela peut impacter le déploiement de vos applications Azure Functions en Isolated worker, car le dossier .azurefunctions est désormais exclu.
Pour forcer upload-artefect à inclure ce dossier caché, nécessaire au fonctionnement de votre application, ajoutez le paramètre « include-hidden-files: true » dans le fichier de configuration .yaml de votre pipeline CI/CD.
Déclenchement inattendu des fonctions utilisant BlobTrigger : Après la migration vers le modèle Isolated worker, si vous utilisez BlobTrigger pour traiter vos blobs, un déclenchement inattendu de votre fonction pourrait survenir, entraînant un re-traitement involontaire des blobs déjà traités.
En effet, pour vérifier si un blob a été traité, le runtime Azure Functions utilise ce qu’on appelle un reçu de blob (blob receipt), créé pour chaque blob traité. Les reçus de blob sont stockés dans un conteneur appelé azure-webjobs-hosts, situé dans le Storage Account de votre fonction Azure.
La migration vers le modèle Isolated worker peut modifier le chemin des reçus de blobs (blob receipts) en raison de changements dans la façon dont le runtime gère leur stockage. Avec ce changement de chemin, les blobs peuvent être déclenchés à nouveau, car le nouveau runtime ne trouve pas les anciens reçus de blobs à l’emplacement attendu.
Pour éviter ce « retriggering », vous pouvez faire l’une de ces actions avant de migrer vos fonctions vers le modèle Isolated worker :
- Archiver les anciens blobs dans un sous-dossier nommé « archives », par exemple. Cela permet de vider votre conteneur de blobs et d’éviter le retraitement des anciens blobs.
- Créer un nouveau compte de stockage spécifiquement dédié au stockage de vos blobs et configurez-le dans la variable d’environnement AzureWebJobStorage. Une bonne pratique consiste à utiliser un compte de stockage distinct de celui de votre fonction Azure. Cela permettra d’éviter les risques de confusion et renforcer la sécurité dans la gestion de vos blobs. Pour plus de détails sur cette recommandation, vous pouvez consulter ce lien.
Conclusion
Le passage du modèle In-Process vers le modèle Isolated worker dans Azure Functions est une étape importante pour bénéficier d’une plus grande flexibilité et indépendance dans le développement de votre solution serverless. Bien que cette migration puisse présenter des défis techniques, elle offre de nombreux avantages, notamment la prise en charge des versions plus récentes de .NET. En suivant les étapes décrites, vous pouvez effectuer cette transition de manière structurée et efficace.
Il est essentiel de tester le code de vos fonctions ligne par ligne, car le comportement de certaines classes ou méthodes pourrait changer avec le modèle Isolated Worker. Cela peut entraîner des erreurs inattendues lors de l’exécution et, dans certains cas, impacter vos données.
Auteur : Yassine CHTOUROU – Consultant Technique .NET & Azure chez Expertime