Ejercicio: Implementación de la simultaneidad optimista

Completado

En el ejercicio anterior, vio cómo el jefe de una sala de redacción solo vio la edición del periodista A. La aplicación permitía que los periodistas sobrescribieran el artículo del periodista B. En este ejercicio, implementará el enfoque optimista para resolver la simultaneidad, de modo que el periodista B no se quede sin trabajo.

En este ejercicio, aprenderá a:

  • Cambiará el método SimulateReporter para usar una etiqueta de entidad
  • Probará la aplicación actualizada

Incorporación de la simultaneidad optimista en el código existente

Sugerencia

Puede usar el botón Copiar para copiar los comandos en el Portapapeles. Para pegarlos, haga clic con el botón derecho en una nueva línea en el terminal de Cloud Shell y seleccione Pegar, o bien use el método abreviado de teclado Mayús+Insert (⌘+V en macOS).

  1. Abra Program.cs:

    code Program.cs
    
  2. En el editor de código, agregue el código para capturar el valor de etiqueta de entidad actual. Desplácese hacia abajo hasta el método SimulateReporter y busque la línea de código que indica Console.WriteLine($"{authorName} begins writing their story...");. Inmediatamente después de esa línea, inserte el código siguiente:

    // Store the current ETag
    var currentETag = downloadResult.Details.ETag;
    Console.WriteLine($"\"{contents}\" has this ETag: {currentETag}");
    

    Este código modifica la aplicación de edición de noticias simulada para registrar la etiqueta de entidad (ETag) del blob en el momento en que se lee.

  3. En SimulateReporter, cambie la llamada a UploadAsync para establecer una condición de solicitud como parte de una instancia de BlobUploadOptions. Cuando se pasa al método de carga, esta condición confirma la ETag antes de guardar los cambios. Este cambio modifica la aplicación de edición de noticias simulado para aplicar la simultaneidad optimista.

    Quite del método el código siguiente:

    // Finally, they save their story back to the blob.
    var story = $"[[{authorName.ToUpperInvariant()}'S STORY]]";
    await blobClient.UploadAsync(BinaryData.FromString(story), true);
    Console.WriteLine($"{authorName} has saved their story to Blob storage. New blob contents: \"{story}\"");
    

    Y reemplácela por este otro:

    try 
    {
        // Finally, they save their story back to the blob.
        var story = $"[[{authorName.ToUpperInvariant()}'S STORY]]";
    
        // Set the If-Match condition to the current ETag
        BlobUploadOptions blobUploadOptions = new()
        {
            Conditions = new BlobRequestConditions()
            {
                IfMatch = currentETag
            }
        };
        await blobClient.UploadAsync(BinaryData.FromString(story), blobUploadOptions);
    
        Console.WriteLine($"{authorName} has saved their story to Blob storage. New blob contents: \"{story}\"");
    }
    catch (RequestFailedException e) when (e.Status == (int)HttpStatusCode.PreconditionFailed)
    {
        // Catch error if the ETag has changed it's value since opening the file
        // This error indicates to the client that another process has updated the blob since the client first retrieved it.
        // The client should fetch the blob again to get the updated content and properties.
        Console.WriteLine($"{authorName}: Sorry, cannot save the file as server returned an error: {e.Message}");
    }
    

    La condición IfMatch = currentETag solicita a Blob Storage que compruebe el valor actual de la ETag para el informe. Si los dos valores coinciden, la operación de escritura se realiza correctamente. Si algún otro proceso ha actualizado el blob, el valor de ETag en el servidor es diferente y se genera una excepción.

  4. Guarde los cambios (CTRL+S) y cierre el editor de código (CTRL+Q).

Prueba de la aplicación nueva

  1. En Cloud Shell, compile y ejecute la aplicación con este comando.

    dotnet run
    

    Los resultados son similares a la salida siguiente:

    The newsroom chief has saved story notes to the blob mslearn-blob-concurrency-demo/newsStory.txt
    
    Reporter A begins work
    Reporter A loads the file and sees the following content: "[[CHIEF'S STORY NOTES]]"
    "[[CHIEF'S STORY NOTES]]" has this ETag: "0x8D6B6DEEC7DED54"
    Reporter A begins writing their story...
    Reporter B begins work
    Reporter B loads the file and sees the following content: "[[CHIEF'S STORY NOTES]]"
    "[[CHIEF'S STORY NOTES]]" has this ETag: "0x8D6B6DEEC7DED54"
    Reporter B begins writing their story...
    Reporter B has finished writing their story
    Reporter B has saved their story to Blob storage. New blob contents: "[[REPORTER B'S STORY]]"
    Reporter A has finished writing their story
    Reporter A Sorry, cannot save the file as server returned an error: The condition specified using HTTP conditional header(s) is not met.
    
    =============================================
    
    Reporters have finished, here's the story saved to the blob:
    [[REPORTER B'S STORY]]
    

    Esta vez, cuando el periodista A termina de escribir su artículo y trata de guardar los cambios, la aplicación no se lo permite. El guardado falla porque el Informador B cambió el archivo desde la última vez que el Informador A lo vio.

Sugerencia

Si no pudo completar esta unidad, puede encontrar una versión totalmente funcional en el directorio OptimisticNewsEditor. Puede ejecutar la aplicación con dotnet run.