Ejercicio: Implementación de la resistencia de la aplicación

Completado

El proyecto eShop tiene dos servicios que se comunican entre sí mediante solicitudes HTTP. El servicio Store llama al servicio Product para obtener la lista de todos los productos actuales disponibles para comprar.

La versión actual de la aplicación no tiene ningún control de resistencia. Si el servicio Product no está disponible, el servicio Store devuelve un error a los clientes y les pide que vuelvan a intentarlo más adelante. Este comportamiento no es una buena experiencia del usuario.

El administrador le pide que agregue resistencia a la aplicación para que el servicio Store vuelva a intentar la llamada al servicio back-end si se produce un error.

En este ejercicio, agregará resistencia a una aplicación nativa de nube existente y probará la corrección.

Abrir el entorno de desarrollo

Puede optar por usar un codespace de GitHub que hospede el ejercicio, o bien hacer el ejercicio localmente en Visual Studio Code.

Para usar un codespace, cree un codespace de GitHub preconfigurado con este vínculo de creación de codespaces.

GitHub tarda unos minutos en crear y configurar el codespace. Cuando se complete el proceso, verá los archivos de código del ejercicio. El código que se va a usar para el resto de este módulo está en el directorio /dotnet-resiliency.

Para usar Visual Studio Code, clone el repositorio https://github.com/MicrosoftDocs/mslearn-dotnet-cloudnative en la máquina local. Después:

  1. Instale cualquier requisito del sistema para ejecutar Dev Container en Visual Studio Code.
  2. Asegúrese de que Docker se está ejecutando.
  3. En una nueva ventana de Visual Studio Code, abra la carpeta del repositorio clonado.
  4. Presione Ctrl+Mayús+P para abrir la paleta de comandos.
  5. Buscar: >Contenedores de desarrollo: Recompilar y volver a abrir en contenedor
  6. Seleccione eShopLite - dotnet-resiliency en la lista desplegable. Visual Studio Code crea el contenedor de desarrollo localmente.

Compilar y ejecutar la aplicación

  1. En el panel inferior, seleccione la pestaña TERMINAL y ejecute el siguiente comando para ir a la raíz del código:

    cd dotnet-resiliency
    
  2. Ejecute el siguiente comando para compilar las imágenes de la aplicación eShop:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. Una vez completada la compilación, ejecute el siguiente comando para iniciar la aplicación:

    docker compose up
    
  4. En el panel inferior, seleccione la pestaña PORTS y, a continuación, en la columna Dirección reenviada de la tabla, seleccione el icono Abrir en el explorador para el puerto Front-end (32000).

    Si ejecuta la aplicación localmente, abra una ventana del explorador para ver http://localhost:32000/products.

  5. La aplicación eShop debe ejecutarse. Seleccione el elemento de menú Productos, debería ver la lista de productos.

    Captura de pantalla en la que se muestra la aplicación eShop en ejecución en un explorador.

Prueba de la resistencia actual

Detenga el servicio de producto para ver lo que sucede con la aplicación.

  1. Vuelva al codespace y, en la pestaña TERMINAL seleccione + para abrir un nuevo terminal bash.

  2. Ejecute el siguiente comando Docker para enumerar los contenedores en ejecución:

    docker ps
    

    Debería ver la lista de contenedores que se están ejecutando actualmente, por ejemplo:

    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. Busque el ID. DE CONTENEDOR del contenedor de productservice. En el ejemplo anterior, el id. es 6ba80f3c7ab0.

  4. Detenga el servicio del producto con este comando Docker:

    docker stop <CONTAINER ID>
    

    Donde el <CONTAINER ID> es el id. que encontró en el paso anterior. Por ejemplo:

    docker stop 6ba80f3c7ab0
    
  5. Vuelva a la pestaña del explorador que ejecuta la aplicación y actualice la página. Debería ver un mensaje de error:

    Hay un problema al cargar nuestros productos. Inténtelo de nuevo más tarde.

  6. Vuelva al codespace y, en el TERMINAL, seleccione el terminal docker y presione Ctrl+C para detener la aplicación. Debería ver lo siguiente:

    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
    

Agregar resistencia a la aplicación

Los primeros pasos para que la aplicación sea más resistente son agregar el paquete NuGet Microsoft.Extensions.Http.Resilience al proyecto. Después, puede usarlo en Program.cs.

Agregar el paquete Microsoft.Extensions.Http.Resilience

  1. En el codespace, en la pestaña TERMINAL, vaya a la carpeta del proyecto Store:

    cd Store
    
  2. Ejecute el comando siguiente para agregar el paquete NuGet de resistencia:

    dotnet add package Microsoft.Extensions.Http.Resilience
    

    Al ejecutar este comando desde el terminal en la carpeta del proyecto de aplicaciones, se agrega la referencia de paquete al archivo del proyecto Store.csproj.

  3. En la barra lateral EXPLORER, seleccione Program.cs.

  4. En la parte superior del archivo, agregue las siguientes instrucciones using:

    using Microsoft.Extensions.Http.Resilience;
    

Agregar una estrategia de resistencia estándar

  1. En la línea 13, antes de ;, agregue este código:

    .AddStandardResilienceHandler()
    

    El código debe ser similar al siguiente:

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

    El código anterior agrega un controlador de resistencia estándar a HTTPClient. El controlador usa toda la configuración predeterminada para la estrategia de resistencia estándar.

    No se necesitan otros cambios de código en la aplicación. Vamos a ejecutar la aplicación y probar la resistencia.

  2. Ejecute los siguientes comandos para recompilar la aplicación eShop:

    cd ..
    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. Cuando se complete la compilación, ejecute el siguiente comando para iniciar la aplicación:

    docker compose up
    
  4. Vuelva a la pestaña del explorador que ejecuta la aplicación y actualice la página del producto. Debería ver la lista de productos.

  5. Vuelva al codespace y, en la pestaña TERMINAL, seleccione el segundo terminal bash. Copie el ID. DE CONTENEDOR del contenedor de productservice.

  6. Vuelva a ejecutar el comando docker stop:

    docker stop <CONTAINER ID>
    
  7. Vuelva a la pestaña del explorador que ejecuta la aplicación y actualice la página del producto. Esta vez, debería tardar un poco más hasta que vea el mensaje de error de las aplicaciones:

    Hay un problema al cargar nuestros productos. Inténtelo de nuevo más tarde.

    Vamos a comprobar los registros para ver si nuestra estrategia de resistencia funciona.

  8. Vuelva al codespace y, en la pestaña TERMINAL, seleccione el terminal docker.

  9. En el terminal, presione Ctrl+C para detener la ejecución de la aplicación.

  10. En los mensajes de registro, desplácese hacia arriba hasta que encuentre referencias 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'
    

    Debería ver muchos mensajes como este; cada uno de ellos es un reintento. El mensaje anterior muestra el segundo intento y el tiempo que tardó en ejecutarse.

Configurar una estrategia de resistencia

Al agregar resistencia a la aplicación, equilibra la necesidad de responder rápidamente a los usuarios con la necesidad de no sobrecargar ningún servicio back-end. Solo puede decidir si las opciones predeterminadas satisfacen sus necesidades de su empresa.

En este ejemplo, le gustaría que el servicio de tienda esperara un poco más, para darle al servicio de tienda la oportunidad de recuperarse.

  1. En la ventana de código de Program.cs, cambie el código de la línea 13 a:

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

    El código anterior cambia el valor predeterminado de la estrategia de reintento para tener un número máximo de retiros a siete. Recuerde que la estrategia es un retroceso exponencial, por lo que el tiempo total es de aproximadamente 5 minutos.

  2. Detenga Docker con Ctrl+C. A continuación, ejecute el siguiente comando para recompilar la aplicación eShop:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. Cuando se complete la compilación, ejecute el siguiente comando para iniciar la aplicación:

    docker compose up
    

    Detenga el contenedor del servicio back-end en el terminal de Bash y actualice eShop. Tenga en cuenta que tarda más tiempo en ver el mensaje de error. Sin embargo, si comprueba los registros podrá ver que la estrategia de reintento solo reintentó cinco veces. El último mensaje de Polly es el siguiente:

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

    El mensaje anterior indica que el tiempo de espera total de solicitudes impide que se alcance el número máximo de reintentos. Para corregir el problema, aumente el tiempo de espera total de la solicitud.

  4. En el terminal, presione Ctrl+C para detener la aplicación.

  5. En la ventana de código de Program.cs, cambie el código de la línea 13 a:

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

    El código anterior cambia el tiempo de espera total de la solicitud a 260 segundos, que ahora es más largo que la estrategia de reintento.

    Con estos cambios debe tener tiempo suficiente para ejecutar la aplicación, detener el servicio de producto, comprobar los registros del terminal para los reintentos, actualizar eShop para ver el mensaje de carga y, por último, reiniciar el servicio de producto para ver correctamente la lista de productos.

  6. Ejecute el comando siguiente para recompilar la aplicación eShop:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  7. Cuando se complete la compilación, ejecute el siguiente comando para iniciar la aplicación:

    docker compose up
    

Probar las nuevas opciones de resistencia

Para poder probar la aplicación en el contenedor, use la extensión Docker. La extensión proporciona una GUI para ver y controlar el estado de los contenedores.

  1. En el menú de la izquierda, seleccione el icono de Docker.

    Captura de pantalla de la extensión Docker que muestra cómo detener el servicio de productos.

  2. En el panel DOCKER, en CONTAINERS, haga clic con el botón derecho en el contenedor products y seleccione Detener.

  3. Vuelva a la pestaña del explorador que ejecuta la aplicación y actualice la página del producto. Debería ver el mensaje Cargando....

  4. Vuelva al codespace y, en la pestaña TERMINAL, seleccione el terminal docker. La estrategia de resistencia funciona.

  5. En el panel DOCKER, en CONTAINERS, haga clic con el botón derecho en el contenedor products y seleccione Iniciar.

  6. Vuelva a la pestaña del explorador que ejecuta la aplicación. Espere y la aplicación debe recuperarse mostrando la lista de los productos.

  7. En el terminal, detenga Docker con Ctrl+C.