Azure Functions en .NET 7 : l’Isolated Process obligatoire

Publié par Antoine BEAUFRERE
Catégorie : .Net / Azure / Azure Functions
23/06/2023

Les Azure Functions constituent un composant majeur des ressources Serverless fournit par Microsoft.

Aperçue la première fois début 2022, la nouvelle version du framework .NET 7 apporte quelques changements pour le cloud d’Azure et notamment un changement peu visible mais pourtant important pour les Azure Functions : l’Isolated Process sera le seul modèle d’hébergement possible.

 

Les Azures Functions

 

Comme le dit si bien la documentation Microsoft :

Tout d’abord, Azure Functions vous permet d’implémenter la logique de votre système dans des blocs de code immédiatement disponibles. Ces blocs de code sont appelés « fonctions ». Différentes fonctions peuvent s’exécuter chaque fois que vous devez répondre à des événements critiques.

Deuxièmement, quand les demandes augmentent, Azure Functions répond à la demande avec autant de ressources et d’instances de fonction que nécessaire, mais uniquement quand il le faut. Quand les demandes diminuent, les ressources supplémentaires et les instances d’application baissent automatiquement.

 

 

L’In Process vs Isolated Process

 

In Process et Isolated Process sont deux modèles d’hébergement différents pour Azure Functions. Le premier exécute le runtime Azure Functions dans le même processus que l’application Web, l’API ou la plateforme qui l’héberge. Cela peut améliorer les performances et l’efficacité des fonctions, mais signifie également que tout problème lié aux fonctions peut affecter le processus d’hébergement global.

L’hébergement Isolated Process, quant à lui, exécute le runtime Azure Functions dans un processus distinct de l’application Web ou de la plate-forme d’hébergement. Cela offre un degré d’isolation plus élevé et peut empêcher les problèmes liés aux fonctions d’affecter le processus d’hébergement. Cependant, cela peut également entraîner une baisse des performances et de l’efficacité par rapport à l’hébergement en cours de processus.

En .NET 6, le choix entre l’hébergement In Process et l’hébergement Isolated Process dépend des exigences et des besoins spécifiques de vos fonctions Azure et de l’environnement d’hébergement. Seulement, à partir de .NET 7, le choix a été fait pour vous.

 

 

Les changements du code

 

Le csproj

Pour commencer, le .csproj se présente légérement différement :
Comparatif du .csproj pour un projet Azure Function

Les choses importantes à retenir dessus sont :

  • le <OutputType> à Exe
  • le changement des dépendances (focus dessus par la suite).

 

Les settings

Un petit passage par le fichier local.settings.json (dans les app settings sur azure) où l’on précise que la fonction est bien en dotnet isolated :
Comparatif des configurations locales d'Azure Function

Cela impliquera donc le même changement dans les App Settings de la Function App.

Le startup / program

On retrouve ensuite un changement sur l’implémentation de la fonction. L’injection de dépendances qui se fait dans un fichier Startup.cs créé en In Process se fait dorénavant dans le fichier Program.cs :

In Process (Startup.cs) :

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(FAProjet.Startup))]

namespace FAProjet
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddLogging();
            builder.Services.AddHttpClient();
            builder.Services.AddSingleton<IApiClientService, ApiClientService>();
        }
    }
}

Isolated Process (Program.cs) :

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var host = new HostBuilder()
    .ConfigureServices(services =>
    {
        services
            .AddLogging()
            .AddHttpClient()
            .AddSingleton<IApiClientService, ApiClientService>();
    })
    .ConfigureFunctionsWorkerDefaults()
    .Build();

host.Run();

 

Les fonctions

Entrons enfin dans le coeur du sujet avec les changements dans les fonctions elles-mêmes qui se résument à deux choses :

  • l’attribut [FunctionName(« … »)] devient (roulement de tambours)  [Function(«  »)] tout simplement,
  • les triggers évoluent dans leurs utilisations

In Process :

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace FunctionAppNet6
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string name = req.Query["name"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            name = name ?? data?.name;

            string responseMessage = string.IsNullOrEmpty(name)
                ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
                : $"Hello, {name}. This HTTP triggered function executed successfully.";

            return new OkObjectResult(responseMessage);
        }
    }
}

 

Isolated Process :

using System.Net;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;

namespace FunctionAppNet7
{
    public class Function1
    {
        [Function("Function1")]
        public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, ILogger logger)
        {
            logger.LogInformation("C# HTTP trigger function processed a request.");

            var response = req.CreateResponse(HttpStatusCode.OK);
            response.Headers.Add("Content-Type", "text/plain; charset=utf-8");

            response.WriteString("Welcome to Azure Functions!");

            return response;
        }
    }
}

Concernant les changements au niveau les triggers, on en a un HTTP trigger ici qui ne fournit plus un HtttpRequest mais à la place un HttpRequestData. En conséquence, renvoyer un statut OK ne se fait plus de la même manière (cf. ci-dessus).

 

Les dépendances

 

Les fonctions In Process et Isolated Process dans Azure Functions ont des dépendances différentes car elles s’exécutent dans des environnements d’exécution différents.

Comme les fonctions In Process s’exécutent dans le même processus que l’hôte, elles ont accès aux dépendances de l’hôte et à toutes les bibliothèques ou paquets supplémentaires qui sont installés dans l’environnement de l’hôte. Les fonctions Isolated, en revanche, s’exécutent dans leur propre processus distinct et disposent donc de leurs propres dépendances et environnement.

Pour vous assurer que le nouveau modèle possède toutes les dépendances nécessaires, vous devez les inclure dans le paquetage de la fonction ou les déployer dans le répertoire bin de l’application de la fonction. Vous pouvez le faire à l’aide d’un fichier zip de déploiement ou en utilisant une méthode de déploiement continu telle que Azure DevOps ou GitHub Actions.

 

 

Les avantages de l’utilisation du Isolated Process

 

Le premier avantage du passage en Isolated Process est une meilleure stabilité et une meilleure disponibilité des fonctions. En exécutant les fonctions dans un processus séparé, les erreurs ne pourront pas affecter l’application web et vice versa. Cela signifie que les fonctions resteront en ligne même si l’application web subit des problèmes, ce qui améliorera la disponibilité de l’application.

Deuxièmement, cela apporte une meilleure isolation des ressources. Chaque fonction disposera de sa propre allocation de mémoire et de ressources CPU, ce qui évitera les conflits entre les fonctions et garantira une meilleure utilisation des ressources. Cela permettra également de mieux gérer les pics de charge en autorisant l’exécution simultanée de plusieurs fonctions.

Le troisième avantage est une meilleure sécurité. Il sera plus difficile pour les attaquants d’accéder aux données et aux ressources de l’application web. Cela augmentera la sécurité de l’application et protégera les données sensibles des utilisateurs.

 

En conclusion, le passage des Azure Functions in process en isolated process apportera plusieurs avantages pour les développeurs, notamment une meilleure stabilité et disponibilité, une meilleure isolation des ressources et une meilleure sécurité. Si vous utilisez Azure Functions dans votre application, vous devriez considérer passer en mode isolated process pour en profiter pleinement.