Ejercicio: Observar la pérdida de datos en una aplicación no compilada para la simultaneidad

Completado

La agencia de noticias tiene una aplicación web que los periodistas del sector financiero usan para enviar artículos al jefe de redacción. La aplicación usa Azure Blob Storage para almacenar los artículos para que el jefe los revise antes de publicarlos.

En primer lugar, el jefe de redacción usa la aplicación de edición para crear notas para los artículos nuevos que quiere que se escriban. Cuando termina, se guardan los cambios. Al guardarlos, las notas se cargan en un blob nuevo. A continuación, los artículos se asignan a un grupo de periodistas. Los periodistas asignados a una historia cargan las notas, realizan cambios en sus áreas de conocimiento y guardan los cambios una vez que han terminado.

Ahora imagine que dos periodistas tienen asignado el mismo artículo. El periodista A comienza a trabajar rápidamente, recuperando las notas y escribiendo una sección larga de la historia. El periodista B comienza poco después, hace una edición en la historia y termina su trabajo primero. El periodista B guarda sus cambios y los confirma en el blob. Más adelante, el periodista A termina su artículo y lo guarda.

El jefe de redacción ha recibido quejas de sus periodistas que dicen que sus artículos se perdieron. Al ejecutar la aplicación, verá que el periodista A no está al tanto del trabajo completado anteriormente por el periodista B y el jefe de la sala de noticias solo ve el trabajo del periodista A.

En este ejercicio, implementará la aplicación y observará los problemas con el enfoque "El último en escribir gana" que se generan a partir de las actualizaciones simultáneas.

Creación de una cuenta de almacenamiento de Azure y almacenamiento de la cadena de conexión

Para experimentar con el código de simultaneidad de Blob Storage, empiece por crear una cuenta de Blob Storage mediante Cloud Shell.

  1. En Cloud Shell, a la derecha, ejecute los siguientes comandos para crear una nueva cuenta de almacenamiento:

    storage=mediastorage$RANDOM
    az storage account create --name $storage --kind StorageV2 -g <rgn>[sandbox resource group name]</rgn> --allow-blob-public-access false
    
  2. A continuación, escriba az storage account show-connection-string para obtener la cadena de conexión y almacénela en una variable de entorno denominada STORAGE_CONNECTION_STRING:

    export STORAGE_CONNECTION_STRING=$(az storage account show-connection-string --name $storage --query connectionString -o tsv)
    

Descarga y revisión del código de ejemplo

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. En Cloud Shell, clone la aplicación desde GitHub:

    git clone https://github.com/MicrosoftDocs/mslearn-support-concurrency-blob-storage.git
    cd mslearn-support-concurrency-blob-storage/src/NewsEditor
    

    Los comandos anteriores lo llevan a la carpeta de aplicación NewsEditor. Hay otras carpetas que tienen el código completado para las unidades del resto del módulo.

  2. Abra el archivo Program.cs en el editor de código:

    code Program.cs
    
  3. Desplácese hacia abajo hasta el método SimulateReporter. Este método simula las actividades de un periodista que trabaja en una versión de la aplicación de edición de noticias que no realiza ningún tipo de administración de simultaneidad activa.

    private static async Task SimulateReporter(BlobContainerClient containerClient, string authorName, TimeSpan writingTime)
    {
        BlobClient blobClient = containerClient.GetBlobClient(blobName);
    
        // First, the reporter retrieves the current contents
        Console.WriteLine($"{authorName} begins work");
    
        var contents = await blobClient.DownloadContentAsync();
        Console.WriteLine($"{authorName} loads the file and sees the following content: \"{contents.Value.Content}\"");
    
        // Next, the author writes their story. This takes some time.
        Console.WriteLine($"{authorName} begins writing their story...");
        await Task.Delay(writingTime);
        Console.WriteLine($"{authorName} has finished writing their story");
    
        // 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}\"");
    }
    

    En la simulación, dos instancias de este método se ejecutarán de manera simultánea con distintos tiempos. Ambos periodistas observarán el mismo contenido cuando descarguen por primera vez el archivo desde el almacenamiento de blobs. El periodista que tarde más en escribir el artículo y guardarlo nuevamente en el blob sobrescribirá sin saberlo el contenido creado por el primer periodista.

  4. Cierre el editor de código (CTRL+Q).

Ejecución de la aplicación de prueba

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

    dotnet run
    
  2. La salida es la 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]]"
    Reporter A begins writing their story...
    Reporter B begins work
    Reporter B loads the file and sees the following content: "[[CHIEF'S STORY NOTES]]"
    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 has saved their story to Blob storage. New blob contents: "[[REPORTER A'S STORY]]"
    
    =============================================
    
    Reporters have finished, here's the story saved to the blob:
    [[REPORTER A'S STORY]]
    

    Estos mensajes de consola permiten seguir el flujo de la aplicación. En este ejemplo, el periodista B ha perdido su trabajo.