Persistance et sérialisation des données dans Durable Functions (Azure Functions)

Le runtime Durable Functions persiste automatiquement les paramètres des fonctions, les valeurs de retour et les autres états dans le hub de la tâche afin de fournir une exécution fiable. Toutefois, le volume et la fréquence des données conservées dans un stockage durable peuvent avoir un impact sur les performances des applications et les coûts des transactions de stockage. Selon le type de données que votre application stocke, il peut être nécessaire de prendre en compte les stratégies de conservation des données et de confidentialité.

Contenu du hub de tâches

Les hubs de tâches stockent l’état actuel des instances et tous les messages en attente :

  • Les états d’instance stockent l’état actuel et l’historique d’une instance. Pour les instances d’orchestration, cet état inclut l’état d’exécution, l’historique d’orchestration, les entrées, les sorties et l’état personnalisé. Pour les instances d’entité, elle inclut l’état de l’entité.
  • Les messages stockent des entrées ou des sorties de fonction, des charges utiles d’événement et des métadonnées qui sont utilisées à des fins internes, comme le routage et la corrélation de bout en bout.

Les messages sont supprimés après traitement, mais les états d’instance persistent, sauf s’ils sont explicitement supprimés par l’application ou par un opérateur. En particulier, un historique d’orchestration reste dans le stockage même une fois l’orchestration terminée.

Pour obtenir un exemple de la façon dont les états et les messages représentent la progression d’une orchestration, consultez l’exemple d’exécution du hub de tâches.

L’emplacement et la façon dont les états et les messages sont représentés dans le stockage dépendent du fournisseur de stockage. Le fournisseur par défaut de Durable Functions est Stockage Azure qui rend persistantes les données dans les files d’attente, les tables et les objets blob dans un compte Stockage Azure que vous spécifiez.

Types de données sérialisées et rendues persistantes

La liste suivante montre les différents types de données qui seront sérialisées et rendues persistantes lors de l’utilisation des fonctionnalités de Durable Functions :

  • Toutes les entrées et sorties des fonctions d’orchestrateur, d’activité et d’entité, y compris les ID et les exceptions non prises en charge
  • Noms des fonctions d’orchestrateur, d’activité et d’entité
  • Noms et charges utiles des événements externes
  • Charges utiles de l’état de l’orchestration personnalisée
  • Messages d’arrêt de l’orchestration
  • Charges utiles du minuteur durable
  • URL, en-têtes et charges utiles de requête HTTP et de réponse durables
  • Appel d’entité et charges utiles de signal
  • Charges utiles d’état d’entité

Travailler avec des données sensibles

Quand vous utilisez le fournisseur Stockage Azure, toutes les données sont chiffrées automatiquement au repos. Toutefois, toute personne ayant accès au compte de stockage peut lire les données sous leur forme non chiffrée. Si vous avez besoin d’une protection renforcée pour les données sensibles, envisagez d’abord de chiffrer les données en utilisant vos propres clés de chiffrement, pour que les données soient rendues persistantes sous leur forme préchiffrée.

Les utilisateurs .NET ont également la possibilité d’implémenter des fournisseurs de sérialisation personnalisés qui fournissent un chiffrement automatique. Vous trouverez un exemple de sérialisation personnalisée avec chiffrement dans cet exemple GitHub.

Notes

Si vous décidez d’implémenter le chiffrement au niveau de l’application, sachez que les orchestrations et les entités peuvent exister pendant une durée indéterminée. Cela est important lorsque vient le moment de permuter vos clés de chiffrement, car une orchestration ou des entités peuvent s’exécuter plus longtemps que votre stratégie de rotation des clés. Si une rotation de clés se produit, la clé utilisée pour chiffrer vos données peut ne plus être disponible pour les déchiffrer lors de la prochaine exécution de l’orchestration ou de l’entité. Le chiffrement des clients est donc recommandé uniquement lorsque des orchestrations et des entités sont censées s’exécuter pendant des périodes relativement courtes.

Personnalisation de la sérialisation et de la désérialisation

Logique de sérialisation par défaut

Durable Functions pour .NET in-process utilise en interne Json.NET pour sérialiser les données d’orchestration et d’entité au format JSON. Les paramètres Json.NET par défaut utilisés sont :

Entrées, sorties et état :

JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.None,
    DateParseHandling = DateParseHandling.None,
}

Exceptions :

JsonSerializerSettings
{
    ContractResolver = new ExceptionResolver(),
    TypeNameHandling = TypeNameHandling.Objects,
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
}

Vous trouverez ici une documentation plus détaillée sur JsonSerializerSettings.

Personnalisation de la sérialisation avec des attributs .NET

Lors de la sérialisation, Json.NET recherche différents attributs sur les classes et les propriétés qui contrôlent la façon dont les données sont sérialisées et désérialisées à partir du format JSON. Si vous possédez le code source du type de données transmis aux API de Durable Functions, pensez à ajouter ces attributs au type pour personnaliser la sérialisation et la désérialisation.

Personnalisation de la sérialisation avec injection de dépendances

Les applications de fonction qui ciblent .NET et s’exécutent sur le runtime de Functions v3 peuvent utiliser l’injection de dépendances pour personnaliser la façon dont les données et les exceptions sont sérialisées. L’exemple de code suivant montre comment utiliser l’injection de dépendances pour remplacer les paramètres de sérialisation Json.NET par défaut en utilisant des implémentations personnalisées des interfaces de service IMessageSerializerSettingsFactory et IErrorSerializerSettingsFactory.

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System.Collections.Generic;

[assembly: FunctionsStartup(typeof(MyApplication.Startup))]
namespace MyApplication
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddSingleton<IMessageSerializerSettingsFactory, CustomMessageSerializerSettingsFactory>();
            builder.Services.AddSingleton<IErrorSerializerSettingsFactory, CustomErrorSerializerSettingsFactory>();
        }

        /// <summary>
        /// A factory that provides the serialization for all inputs and outputs for activities and
        /// orchestrations, as well as entity state.
        /// </summary>
        internal class CustomMessageSerializerSettingsFactory : IMessageSerializerSettingsFactory
        {
            public JsonSerializerSettings CreateJsonSerializerSettings()
            {
                // Return your custom JsonSerializerSettings here
            }
        }

        /// <summary>
        /// A factory that provides the serialization for all exceptions thrown by activities
        /// and orchestrations
        /// </summary>
        internal class CustomErrorSerializerSettingsFactory : IErrorSerializerSettingsFactory
        {
            public JsonSerializerSettings CreateJsonSerializerSettings()
            {
                // Return your custom JsonSerializerSettings here
            }
        }
    }
}