Compartilhar via


Segurança do thread e gerenciamento de tempo de vida do cliente para objetos do SDK do Azure

Este artigo ajuda você a entender os problemas de segurança de thread ao usar o SDK do Azure. Ele também discute como o design do SDK afeta o gerenciamento de tempo de vida do cliente. Você aprenderá por que é desnecessário descartar objetos de cliente do SDK do Azure.

Acesso thread-safe

Todos os objetos de cliente do SDK do Azure são thread-safe e independentes uns dos outros. Esse design garante que a reutilização de instâncias de cliente seja sempre segura, mesmo entre threads. Por exemplo, o código a seguir inicia várias tarefas, mas é thread seguro:

var client = new SecretClient(
    new Uri("<secrets_endpoint>"), new DefaultAzureCredential());

foreach (var secretName in secretNames)
{
    // Using clients from parallel threads
    Task.Run(() => Console.WriteLine(client.GetSecret(secretName).Value));
}

Os objetos de modelo usados pelos clientes do SDK, sejam modelos de entrada ou saída, não são thread-safe por padrão. A maioria dos casos de uso envolvendo objetos de modelo usa apenas um único thread. Portanto, o custo de implementar a sincronização como um comportamento padrão é muito alto para esses objetos. O código a seguir ilustra um bug no qual acessar um modelo de vários threads pode causar um comportamento indefinido:

KeyVaultSecret newSecret = client.SetSecret("secret", "value");

foreach (var tag in tags)
{
    // Don't use model type from parallel threads
    Task.Run(() => newSecret.Properties.Tags[tag] = CalculateTagValue(tag));
}

client.UpdateSecretProperties(newSecret.Properties);

Para acessar o modelo de threads diferentes, você deve implementar seu próprio código de sincronização. Por exemplo:

KeyVaultSecret newSecret = client.SetSecret("secret", "value");

// Code omitted for brevity

foreach (var tag in tags)
{
    Task.Run(() =>
    {
        lock (newSecret)
        {
            newSecret.Properties.Tags[tag] = CalculateTagValue(tag);
        }
    );
}

client.UpdateSecretProperties(newSecret.Properties);

Tempo de vida do cliente

Como os clientes do SDK do Azure são thread-safe, não há razão para construir vários objetos de cliente do SDK para um determinado conjunto de parâmetros de construtor. Trate objetos de cliente do SDK do Azure como singletons uma vez construídos. Essa recomendação geralmente é implementada registrando objetos de cliente do SDK do Azure como singletons no contêiner de IoC (Inversão de Controle) do aplicativo. A DI (injeção de dependência) é usada para obter referências ao objeto cliente do SDK. O exemplo a seguir mostra um registro de objeto de cliente singleton:

var builder = Host.CreateApplicationBuilder(args);

var endpoint = builder.Configuration["SecretsEndpoint"];
var blobServiceClient = new BlobServiceClient(
    new Uri(endpoint), new DefaultAzureCredential());

builder.Services.AddSingleton(blobServiceClient);

Veja mais informações sobre a implementação da DI com o SDK do Azure, consulte Injeção de dependência com o SDK do Azure para .NET.

Como alternativa, você pode criar uma instância de cliente do SDK e fornecê-la a métodos que exigem um cliente. O objetivo é evitar instanciações desnecessárias do mesmo objeto cliente do SDK com os mesmos parâmetros. É desnecessário e desperdiçador.

Os clientes não são descartáveis

Duas perguntas finais que muitas vezes aparecem são:

  • Preciso descartar objetos de cliente do SDK do Azure quando terminar de usá-los?
  • Por que os objetos de cliente do SDK do Azure baseados em HTTP não são descartáveis?

Internamente, todos os clientes do SDK do Azure usam uma única instância compartilhada HttpClient. Os clientes não criam outros recursos que precisam ser liberados ativamente. A instância compartilhada HttpClient persiste durante todo o tempo de vida do aplicativo.

// Both clients reuse the shared HttpClient and don't need to be disposed
var blobClient = new BlobClient(new Uri(sasUri));
var blobClient2 = new BlobClient(new Uri(sasUri2));

É possível fornecer uma instância personalizada de HttpClient para um objeto cliente do SDK do Azure. Nesse caso, você se torna responsável por gerenciar o tempo de vida HttpClient e eliminá-lo corretamente no momento certo.

var httpClient = new HttpClient();

var clientOptions = new BlobClientOptions()
{
    Transport = new HttpClientTransport(httpClient)
};

// Both clients would use the HttpClient instance provided in clientOptions
var blobClient = new BlobClient(new Uri(sasUri), clientOptions);
var blobClient2 = new BlobClient(new Uri(sasUri2), clientOptions);

// Code omitted for brevity

// You're responsible for properly disposing httpClient some time later
httpClient.Dispose();

Outras diretrizes para gerenciar e descartar corretamente instâncias HttpClient podem ser encontradas na documentação HttpClient.

Confira também