Exercício - Implementar resiliência de aplicativos

Concluído

O projeto eShop tem dois serviços que se comunicam entre si usando solicitações HTTP. O Store serviço chama o Product serviço para obter a lista de todos os produtos atuais disponíveis para compra.

A versão atual do aplicativo não tem manipulação de resiliência. Se o Product serviço não estiver disponível, o Store serviço devolve um erro aos clientes e pede-lhes para tentarem novamente mais tarde. Esse comportamento não é uma boa experiência do usuário.

Seu gerente solicita que você adicione resiliência ao aplicativo, para que o Store serviço tente novamente a chamada de serviço de back-end se ela falhar.

Neste exercício, você adiciona resiliência a um aplicativo nativo da nuvem existente e testa sua correção.

Abra o ambiente de desenvolvimento

Você pode optar por usar um espaço de código GitHub que hospeda o exercício ou concluí-lo localmente no Visual Studio Code.

Para usar um codespace, crie um Codespace GitHub pré-configurado com este link de criação do Codespace.

O GitHub leva vários minutos para criar e configurar o espaço de código. Quando o processo for concluído, você verá os arquivos de código para o exercício. O código a ser usado para o restante deste módulo está no diretório /dotnet-resiliency .

Para usar o Visual Studio Code, clone o https://github.com/MicrosoftDocs/mslearn-dotnet-cloudnative repositório para sua máquina local. Em seguida:

  1. Instale quaisquer requisitos do sistema para executar o Dev Container no Visual Studio Code.
  2. Verifique se o Docker está em execução.
  3. Em uma nova janela do Visual Studio Code, abra a pasta do repositório clonado
  4. Pressione Ctrl+Shift+P para abrir a paleta de comandos.
  5. Pesquisa: >Contêineres de desenvolvimento: reconstruir e reabrir no contêiner
  6. Selecione eShopLite - dotnet-resiliency na lista suspensa. O Visual Studio Code cria seu contêiner de desenvolvimento localmente.

Compilar e executar a aplicação

  1. No painel inferior, selecione a guia TERMINAL e execute o seguinte comando vá para a raiz do código:

    cd dotnet-resiliency
    
  2. Execute o seguinte comando para criar as imagens do aplicativo eShop:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. Quando a compilação for concluída, execute o seguinte comando para iniciar o aplicativo:

    docker compose up
    
  4. No painel inferior, selecione a guia PORTAS e, em seguida, na coluna Endereço Encaminhado da tabela, selecione o ícone Abrir no navegador para a porta Front-End (32000).

    Se você estiver executando o aplicativo localmente, abra uma janela do navegador para exibir http://localhost:32000/productso .

  5. A aplicação eShop deve estar em execução. Selecione o item de menu Produtos , você verá a lista de produtos.

    Captura de ecrã a mostrar a aplicação eShop em execução num browser.

Testar a resiliência atual

Pare o serviço do produto para ver o que acontece com o aplicativo.

  1. Volte ao seu codespace e, na guia TERMINAL , selecione + para abrir um novo terminal bash.

  2. Execute o seguinte comando docker para listar os contêineres em execução:

    docker ps
    

    Você deve ver a lista de contêineres em execução no momento, por exemplo:

    CONTAINER ID   IMAGE                                                                            COMMAND                  CREATED          STATUS          PORTS                                                        NAMES
    c08285e8aaa4   storeimage                                                                       "dotnet Store.dll"       8 minutes ago    Up 8 minutes    80/tcp, 443/tcp, 0.0.0.0:5902->8080/tcp, :::5902->8080/tcp   eshoplite-frontend-1
    6ba80f3c7ab0   productservice                                                                   "dotnet Products.dll"    8 minutes ago    Up 8 minutes    80/tcp, 443/tcp, 0.0.0.0:5200->8080/tcp, :::5200->8080/tcp   eshoplite-backend-1
    cd0c822a5222   vsc-eshoplite-958868d22c9851dd911b2423199bfc782861d1a8f7afac48e5096a1b7516082f   "/bin/sh -c 'echo Co…"   27 minutes ago   Up 27 minutes     
    
  3. Procure o ID do CONTAINER para o contêiner productservice . No exemplo acima, o ID é 6ba80f3c7ab0.

  4. Pare o serviço do produto com este comando docker:

    docker stop <CONTAINER ID>
    

    Onde o <CONTAINER ID> é o ID que você encontrou na etapa anterior. Por exemplo:

    docker stop 6ba80f3c7ab0
    
  5. Volte para a guia do navegador que executa o aplicativo e atualize a página. Deverá ver uma mensagem de erro:

    Existe um problema ao carregar os nossos produtos. Tente novamente mais tarde.

  6. Volte para o seu espaço de código e, no TERMINAL , selecione o terminal docker e pressione Ctrl+C para parar o aplicativo. Deverá ver:

    Gracefully stopping... (press Ctrl+C again to force)
    Aborting on container exit...
    [+] Stopping 2/1
     ✔ Container eshoplite-frontend-1  Stopped                                                                      0.3s 
     ✔ Container eshoplite-backend-1   Stopped                                                                      0.0s 
    canceled
    

Adicionar resiliência ao aplicativo

As primeiras etapas para tornar seu aplicativo mais resiliente são adicionar o Microsoft.Extensions.Http.Resilience pacote NuGet ao projeto. Você pode usá-lo em Program.cs.

Adicione o pacote Microsoft.Extensions.Http.Resilience

  1. No seu espaço de código, na guia TERMINAL , navegue até a pasta do projeto Store :

    cd Store
    
  2. Execute o seguinte comando para adicionar o pacote NuGet de resiliência:

    dotnet add package Microsoft.Extensions.Http.Resilience
    

    A execução deste comando a partir do terminal na pasta do projeto apps adiciona a referência do pacote ao arquivo de projeto Store.csproj .

  3. Na barra lateral do EXPLORER, selecione Program.cs.

  4. Na parte superior do arquivo, adicione a seguinte instrução using:

    using Microsoft.Extensions.Http.Resilience;
    

Adicionar uma estratégia de resiliência padrão

  1. Na Linha 13, antes de ;, adicione este código:

    .AddStandardResilienceHandler()
    

    O código deverá ser semelhante a:

    builder.Services.AddHttpClient<ProductService>(c =>
    {
        var url = builder.Configuration["ProductEndpoint"] ?? throw new InvalidOperationException("ProductEndpoint is not set");
    
        c.BaseAddress = new(url);
    }).AddStandardResilienceHandler();
    

    O código acima adiciona um manipulador de resiliência padrão ao HTTPClient. O manipulador usa todas as configurações padrão para a estratégia de resiliência padrão.

    Nenhuma outra alteração de código é necessária para seu aplicativo. Vamos executar o aplicativo e testar a resiliência.

  2. Execute os seguintes comandos para reconstruir o aplicativo eShop:

    cd ..
    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. Quando a compilação for concluída, execute o seguinte comando para iniciar o aplicativo:

    docker compose up
    
  4. Volte para a guia do navegador que executa o aplicativo e atualize a página do produto. Você deve ver a lista de produtos.

  5. Volte ao seu codespace e, no separador TERMINAL , selecione o segundo terminal bash. Copie o ID do CONTAINER para o contêiner productservice .

  6. Execute novamente o comando docker stop:

    docker stop <CONTAINER ID>
    
  7. Volte para a guia do navegador que executa o aplicativo e atualize a página do produto. Desta vez, deve demorar um pouco mais até ver a mensagem de erro das aplicações:

    Há um problema ao carregar os nossos produtos. Tente novamente mais tarde.

    Vamos verificar os logs para ver se nossa estratégia de resiliência está funcionando.

  8. Volte ao seu codespace e, na guia TERMINAL, selecione o terminal docker.

  9. No terminal, pressione Ctrl+C para interromper a execução do aplicativo.

  10. Nas mensagens de registo, desloque-se para cima até encontrar referências a Polly.

    eshoplite-frontend-1  | warn: Polly[3]
    eshoplite-frontend-1  |       Execution attempt. Source: 'ProductService-standard//Standard-Retry', Operation Key: '', Result: 'Name or service not known (backend:8080)', Handled: 'True', Attempt: '2', Execution Time: '27.2703'
    

    Você deve ver muitas mensagens como esta; cada uma é uma tentativa de repetição. A mensagem acima mostra a segunda tentativa e o tempo que levou para ser executada.

Configurar uma estratégia de resiliência

Ao adicionar resiliência ao seu aplicativo, você está equilibrando a necessidade de responder rapidamente aos usuários com a necessidade de não sobrecarregar nenhum serviço de back-end. Somente você pode decidir se as opções padrão atendem às necessidades da sua empresa.

Neste exemplo, você gostaria que o serviço da loja esperasse um pouco mais, para dar ao serviço da loja uma chance de recuperação.

  1. Na janela de código para Program.cs, altere o código na linha 13 para:

    .AddStandardResilienceHandler(options =>
    {
        options.Retry.MaxRetryAttempts = 7;
    });
    

    O código acima altera o padrão da estratégia de repetição para ter um número máximo de aposentados para sete. Lembre-se que a estratégia é um recuo exponencial, então o tempo total é de cerca de 5 minutos.

  2. Pare o docker com Ctrl+C. Em seguida, execute o seguinte comando para reconstruir o aplicativo eShop:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. Quando a compilação for concluída, execute o seguinte comando para iniciar o aplicativo:

    docker compose up
    

    Pare o contêiner de serviço de back-end no terminal bash e atualize a eShop. Observe que leva mais tempo para ver a mensagem de erro. Se você verificar os registros, porém, poderá ver que a estratégia de repetição só foi repetida cinco vezes. A última mensagem de Polly é:

    Polly.Timeout.TimeoutRejectedException: The operation didn't complete within the allowed timeout of '00:00:30'.
    

    A mensagem acima informa que o tempo limite total da solicitação impede que o número máximo de novas tentativas seja atingido. Você pode corrigir o problema aumentando o tempo limite total da solicitação.

  4. No terminal, pressione Ctrl+C para parar o aplicativo.

  5. Na janela de código para Program.cs, altere o código na linha 13 para:

    .AddStandardResilienceHandler(options =>
    {
        options.Retry.RetryCount = 7;
        options.TotalRequestTimeout = new HttpTimeoutStrategyOptions
        {
            Timeout = TimeSpan.FromMinutes(5)
        };
    });
    

    O código acima altera o tempo limite total da solicitação para 260 segundos, que agora é mais longo do que a estratégia de repetição.

    Com essas alterações, você deve ter tempo suficiente para executar o aplicativo, parar o serviço do produto, verificar os logs do terminal para tentativas de novas tentativas, atualizar a eShop para ver a mensagem de carregamento e, finalmente, reiniciar o serviço do produto para ver com êxito a lista de produtos.

  6. Execute o seguinte comando para reconstruir o aplicativo eShop:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  7. Quando a compilação for concluída, execute o seguinte comando para iniciar o aplicativo:

    docker compose up
    

Testar as novas opções de resiliência

Para ajudar a testar o aplicativo em seu contêiner, use a extensão Docker. A extensão fornece uma GUI para visualizar e controlar o estado dos contêineres.

  1. No menu à esquerda, selecione o ícone do Docker .

    Uma captura de tela da extensão docker, mostrando como parar o serviço de produtos.

  2. No painel DOCKER, em CONTÊINERES, clique com o botão direito do mouse no contêiner de produtos e selecione Parar.

  3. Volte para a guia do navegador que executa o aplicativo e atualize a página do produto. Deverá ver a mensagem Carregando...

  4. Volte ao seu codespace e, na guia TERMINAL , selecione o terminal docker . A estratégia de resiliência está a funcionar.

  5. No painel DOCKER, em CONTÊINERES, clique com o botão direito do mouse no contêiner de produtos e selecione Iniciar.

  6. Volte para a guia do navegador que executa o aplicativo. Aguarde e o aplicativo deve recuperar mostrando a lista dos produtos.

  7. No Terminal, pare o docker com Ctrl+C.