[Preview] Web Jobs en Windows Azure Web sites

Ayer estuve revisando una nueva característica, aún en preview, para Windows Azure Web sites llamada Web Jobs. Gracias a ella, seremos capaces de lanzar procesos en segundo plano, ya sea manual o automáticamente.
Hace unas semanas vimos Scheduler (también en preview) y, si bien es cierto que la idea se aproxima, debemos ser conscientes de que no se trata exactamente de lo mismo, aunque cabe mencionar que estos web jobs se apoyan justamente en este otro servicio para su modo recurrente.

El job

Para trabajar con este servicio, debemos adjuntar un ejecutable que cumpla con uno de los siguientes tipos:

  • .cmd, .bat, .exe (windows cmd)
  • .sh (bash)
  • .php (php)
  • .py (python)
  • .js (node)

En mi caso, he creado una aplicación de consola:

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Configuration;
using System.Diagnostics;
using System.Linq;

namespace WebJobStorage
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime boundary = DateTime.Now.AddDays(-15);

            var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["StorageAccount"].ConnectionString);
            var blobClient = storageAccount.CreateCloudBlobClient();

            var container = blobClient.GetContainerReference("stuff");

            var blobs = container.ListBlobs(useFlatBlobListing: true).OfType<CloudBlockBlob>();

            foreach (var blob in blobs)
            {
                if (blob.Properties.LastModified < boundary)
                {
                    Console.WriteLine("Warning: {0} is old", blob.Uri);
                }
            }

        }
    }
}

La única operación que realizo en este código es marcar un límite de 15 días, accedo a una cuenta de Windows Azure Storage y dentro de la misma a un contenedor llamado stuff. Busco dentro del mismo para recuperar todos los blobs y, por cada uno de ellos, compruebo cuál lleva sin modificarse más de 15 días. En este ejemplo sólo se mostrará por consola un mensaje de tipo Warning con la Uri del elemento en cuestión.

He compilado este código en modo Release y he comprimido todo el contenido de la carpeta que se genera en un .zip. Ahora lo que necesito es crear un web job que ejecute este código por mi.

Web Jobs en el portal

Una vez que tenemos el proceso que queremos lanzar, accedemos al portal de Windows Azure y seleccionamos el web site al que queremos asociar el job. En él veremos que existe un nuevo apartado llamado Web Jobs PREVIEW:

Web Jobs section WA Web Sites

Hacemos clic en la acción ADD A NEW JOB o en el botón ADD, en la parte inferior de la pantalla. Aparecerá el siguiente cuadro de diálogo:

Basic web job settings

  • NAME: Nombre del job. El mismo no puede contener ningún carácter especial, a excepción de – y _.
  • CONTENT (ZIP FILES – 200MB MAX): Localizamos el archivo .zip que generamos en el paso anterior y lo adjuntamos.
  • HOW TO RUN: Por último, debemos establecer de qué forma se ejecuta este proceso. A día de hoy existen tres opciones: Que siempre se esté ejecutando, programada (haciendo uso del servicio Scheduler mencionado anteriormente) o bajo demanda.

En este ejemplo he creado uno llamado jobstorage que será lanzado bajo demanda.

jobstorage-run-once on demand

En la imagen anterior se muestra lo que podemos ver una vez creado el job. En la parte inferior de la pantalla, cuando estamos posicionados sobre el elemento, nos permite ejecutarlo bajo demanda las veces que necesitemos. En la tabla podemos ver el estado del mismo, el tipo de ejecución que tiene, cuándo fue la última vez que se lanzó, el resultado de la última operación y, por último, un enlace al log de job. Si hacemos clic sobre él, accederemos a un segundo sitio donde podremos descargar el archivo de registro de cada una de las ejecuciones:

Triggered job history for jobstorage

El contenido de cualquiera de ellos es similar al siguiente:

Output Web Job

Como podemos observar, aparece información propia del servicio y, además, una línea por cada uno de los elementos que no cumple con el límite establecido en mi aplicación de consola.

Espero que haya sido de utilidad.

¡Saludos!

Renombrar/Mover/Copiar un blob de Windows Azure Storage

Uno de los escenarios más comunes cuando trabajamos con blobs es dar la posibilidad al usuario de modificar el nombre del archivo, moverlo a otra ubicación o simplemente realizar una copia del mismo. A día de hoy no existe un método renombrar o mover, ya que, en realidad, estas acciones se basan en copiar el archivo de origen en otro blob con el nuevo nombre y, una vez completado, eliminar el original.

Una forma de llevar a cabo esta operación puede ser la siguiente:

        public void RenameBlob(string reference, string newName, string container)
        {
            var blobClient = _account.CreateCloudBlobClient();

            var oldBlob = blobClient.GetBlobReferenceFromServer(new Uri(reference));
            var newBlob = blobClient.GetContainerReference(container).GetBlockBlobReference(newName);

            newBlob.StartCopyFromBlob(oldBlob.Uri);

            while (newBlob.CopyState.Status == CopyStatus.Pending)
            {
                Console.WriteLine("{0} bytes copied from {1}", newBlob.CopyState.BytesCopied, newBlob.CopyState.TotalBytes);
                Thread.Sleep(1000);
            }

            if (newBlob.CopyState.Status != CopyStatus.Success)
                throw new Exception(newBlob.CopyState.StatusDescription);

            oldBlob.Delete();
        }

En el código anterior se utiliza la Uri del blob original (reference), el nuevo nombre que queremos asociar al resultante (newName) y el container donde queremos alojarlo (no tiene por qué ser el mismo que el de origen).

Al recuperar el blob original, estoy haciendo uso de GetBlobReferenceFromServer a nivel de blobClient, donde es obligatorio pasarle la ubicación completa del recurso. Si cometemos el error de intentar recuperar un blob que no existe en dicha ubicación este método lanzará una excepción. En el caso del nuevo blob, al no existir todavía, utilizamos GetBlockBlobReference a nivel de container, con el objetivo de conseguir una URL válida para nuestro nuevo recurso.

Una vez que tenemos los dos elementos, a través de StartCopyFromBlob comenzamos la copia en la nueva ubicación. Dentro de CopyState tenemos una serie de propiedades que nos permiten conocer el estado en el que se encuentra la copia, los bytes que lleva copiados hasta el momento, etcétera. En el código compruebo cada segundo si el proceso sigue estando pendiente y, en ese caso, muestro por consola la cantidad de bytes que lleva copiados hasta ese momento. Una vez cambia de estado, en el caso de que el siguiente sea distinto de Success lanzamos una excepción para visualizar el motivo por el cual la copia no se ha realizado correctamente (Abortion o Failure).

El paso final, si se trata de renombrar o mover de ubicación, sería eliminar el blob original. En el caso de que sólo queramos realizar una copia, basta con omitir la línea oldBlob.Delete();

Espero que sea de utilidad.

¡Saludos!

Modificar los permisos de un container de Windows Azure Storage desde el portal

En los inicios de la plataforma Windows Azure, una de las mayores quejas por parte de los desarrolladores era la poca interacción con el servicio Windows Azure Storage desde el portal. Lo cierto es que ha cambiado de forma considerable y, si bien hay acciones que incluso nos podrían suponer desplegar de nuevo la solución que consumía este servicio, desde hace tiempo podemos realizar algunas gestiones desde el portal.

En un post anterior sobre el Acceso temporal a un blob privado de Windows Azure Storage, comentaba que era posible desde Visual Studio modificar los permisos de un contenedor, seleccionando el mismo en la ventana Server Explorer y modificando sus propiedades:

Modificacion de permisos desde Visual Studio

Esta misma acción es posible desde el portal para aquellos que no sean desarrolladores. Para ello basta con seleccionar la cuenta donde está el contenedor que necesitamos modificar, accedemos al apartado CONTAINERS, seleccionamos el indicado y hacemos clic en EDIT para modificar los permisos:

Edit container metadata

¡Saludos!