Persistência e serialização de dados em funções duráveis (Azure Functions)

O tempo de execução das Funções Duráveis persiste automaticamente os parâmetros da função, os valores de retorno e outros estados para o hub de tarefas para fornecer uma execução confiável. No entanto, a quantidade e a frequência dos dados persistidos para o armazenamento durável podem afetar o desempenho do aplicativo e os custos de transação de armazenamento. Dependendo do tipo de dados que seu aplicativo armazena, as políticas de retenção de dados e privacidade também podem precisar ser consideradas.

Conteúdo do Hub de Tarefas

Os hubs de tarefas armazenam o estado atual das instâncias e quaisquer mensagens pendentes:

  • Os estados da instância armazenam o status atual e o histórico de uma instância. Para instâncias de orquestração, esse estado inclui o estado de tempo de execução, o histórico de orquestração, entradas, saídas e status personalizado. Para instâncias de entidade, inclui o estado da entidade.
  • As mensagens armazenam entradas ou saídas de funções, cargas úteis de eventos e metadados que são usados para fins internos, como roteamento e correlação de ponta a ponta.

As mensagens são excluídas depois de processadas, mas os estados da instância persistem, a menos que sejam explicitamente excluídas pelo aplicativo ou por um operador. Em particular, um histórico de orquestração permanece armazenado mesmo depois que a orquestração é concluída.

Para obter um exemplo de como estados e mensagens representam o progresso de uma orquestração, consulte o exemplo de execução do hub de tarefas.

Onde e como os estados e as mensagens são representados no armazenamento dependem do provedor de armazenamento. O provedor padrão do Durable Functions é o Armazenamento do Azure, que persiste dados para filas, tabelas e blobs em uma conta de Armazenamento do Azure que você especificar.

Tipos de dados serializados e persistentes

A lista a seguir mostra os diferentes tipos de dados que serão serializados e persistentes ao usar recursos de funções duráveis:

  • Todas as entradas e saídas de funções de orquestrador, atividade e entidade, incluindo quaisquer IDs e exceções não tratadas
  • Nomes de funções de orquestrador, atividade e entidade
  • Nomes de eventos externos e cargas úteis
  • Cargas úteis de status de orquestração personalizadas
  • Mensagens de encerramento de orquestração
  • Cargas úteis duráveis do temporizador
  • URLs, cabeçalhos e cargas úteis de solicitação e resposta HTTP duráveis
  • Cargas úteis de chamada e sinal de entidade
  • Cargas úteis do estado da entidade

Trabalhar com dados confidenciais

Ao usar o provedor de Armazenamento do Azure, todos os dados são automaticamente criptografados em repouso. No entanto, qualquer pessoa com acesso à conta de armazenamento pode ler os dados em sua forma não criptografada. Se você precisar de uma proteção mais forte para dados confidenciais, considere primeiro criptografar os dados usando suas próprias chaves de criptografia para que os dados persistam em sua forma pré-criptografada.

Como alternativa, os usuários do .NET têm a opção de implementar provedores de serialização personalizados que fornecem criptografia automática. Um exemplo de serialização personalizada com criptografia pode ser encontrado neste exemplo do GitHub.

Nota

Se você decidir implementar a criptografia no nível do aplicativo, esteja ciente de que orquestrações e entidades podem existir por períodos indefinidos de tempo. Isso é importante na hora de girar suas chaves de criptografia porque uma orquestração ou entidades podem ser executadas por mais tempo do que sua política de rotação de chaves. Se ocorrer uma rotação de chaves, a chave usada para criptografar seus dados pode não estar mais disponível para descriptografá-los na próxima vez que sua orquestração ou entidade for executada. Portanto, a criptografia do cliente é recomendada apenas quando se espera que orquestrações e entidades sejam executadas por períodos de tempo relativamente curtos.

Personalizando a serialização e a desserialização

Lógica de serialização padrão

O Durable Functions for .NET em processo usa internamente Json.NET para serializar dados de orquestração e entidade para JSON. As configurações de Json.NET padrão usadas são:

Entradas, saídas e estado:

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

Exceções:

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

Leia a documentação mais detalhada aqui JsonSerializerSettings .

Personalizando a serialização com atributos .NET

Durante a serialização, Json.NET procura vários atributos em classes e propriedades que controlam como os dados são serializados e desserializados do JSON. Se você possui o código-fonte do tipo de dados passado para APIs de Funções Duráveis, considere adicionar esses atributos ao tipo para personalizar a serialização e a desserialização.

Personalizando a serialização com injeção de dependência

Os aplicativos de função destinados ao .NET e executados no tempo de execução do Functions V3 podem usar a DI (Injeção de Dependência) para personalizar como os dados e as exceções são serializados. O código de exemplo a seguir demonstra como usar DI para substituir as configurações de serialização de Json.NET padrão usando implementações personalizadas das IMessageSerializerSettingsFactory interfaces e IErrorSerializerSettingsFactory de serviço.

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