Este artículo proviene de un motor de traducción automática.

Computación en nube

Sincronización de múltiples nodos en Windows Azure

Josh Twist

Descargar el ejemplo de código

La nube representa un turno de tecnología principales, y muchos expertos del sector predecir este cambio es una escala que se consulte únicamente cada 12 años o menos. Este nivel de excitación es sorprendente apenas si tiene en cuenta las numerosas ventajas en que la nube promete: reduce considerablemente los costos, alta disponibilidad y escalabilidad casi infinita, en ejecución para el nombre y otras.

Por supuesto, un cambio de este tipo también presenta el sector con una serie de desafíos, no menos las que se enfrentan hoy los desarrolladores. Por ejemplo, ¿cómo se crean los sistemas que están colocados de forma óptima para aprovechar las características exclusivas de la nube?

Afortunadamente, Microsoft de febrero inicia la plataforma Windows Azure, que contiene un número de elementos con el tamaño adecuado para admitir la creación de aplicaciones que admiten grandes cantidades de usuarios al tiempo restante de alta disponibilidad. Sin embargo, para que cualquier aplicación alcanzar todo su potencial cuando se implementa en la nube, en los programadores del sistema para aprovechar las ventajas de lo que es posiblemente característica mayor de la nube es la onus: elasticidad.

Elasticidad es una propiedad de la nube de plataformas que permite a los recursos adicionales (informática de alimentación, almacenamiento y así sucesivamente) se aprovisionado a petición, ya que permite agregar servidores adicionales para el conjunto de servidores Web en cuestión de minutos, no meses. Igualmente importante es la posibilidad de quitar estos recursos rápidamente.

Un principio clave de la nube de informática es el modelo de negocio pay-as-you-go, donde sólo pagas lo utiliza. Con Windows Azure, sólo pagas el tiempo que se implementa un nodo (un Web o la función de trabajo que se ejecuta en una máquina virtual), lo que reduce el número de nodos cuando ya no son necesarios o durante los períodos más bajo de la empresa, que da como resultado un ahorro de costos directos.

Por lo tanto, es muy importante que los desarrolladores crear sistemas elásticos que reaccionen automáticamente a la prestación de hardware adicional, con un entrada mínimo o la configuración necesaria de los administradores de sistemas.

Escenario 1: Crear números de pedido

Recientemente, tuve la suerte de trabajar en una prueba de concepto que se examinó el desplazamiento de una infraestructura de aplicación Web existente a la nube mediante Windows Azure.

Dada la naturaleza con particiones de datos de la aplicación, era el principal candidato para la tabla de almacenamiento de Windows Azure. Este mecanismo de almacenamiento de información simple pero de alto rendimiento, gracias a su compatibilidad para una escalabilidad casi infinita, fue una elección ideal, con sólo un inconveniente importante sobre los identificadores únicos.

La aplicación de destino permite a los clientes realizar un pedido y recuperar su número de pedido. Con SQL Server o SQL Azure, Would have sido fácil generar un identificador simple, numérico y exclusivo, pero el almacenamiento de información de Windows Azure tabla no ofrece las claves principales de incremento automático. En su lugar, 
developers mediante el almacenamiento de Windows Azure tabla puede crear un GUID y utilícelo como “ clave ” en la tabla:

505EAB78-6976-4721-97E4-314C76A8E47E

El problema con el uso de los GUID es que son difíciles para trabajar con los seres humanos. Imagine que tener que lee el número de orden GUID a un operador a través del teléfono, o tome nota del mismo en el diario. Por supuesto, los GUID deben ser únicos en cada contexto al mismo tiempo, por lo que son bastante complejas. Por otro lado, el número de pedido, sólo tiene que ser único en la tabla Orders.

Creación de un simple identificador exclusivo de Windows Azure

Se considera un número relativamente sencilla soluciones al problema de GUID:

  1. Utilice SQL Azure para generar identificadores únicos: Para una serie de razones, la prueba de concepto ya había descuentan Azure de SQL en favor de la tabla de almacenamiento de Windows Azure, principalmente debido a la necesidad de que el sistema para escalar en horizontal para el número de nodos, cada uno con muchos subprocesos que se ejecutan en los datos.
  2. Utilice el almacenamiento de información Blob para administrar un valor incremento: Almacenar un contador de central de almacenamiento de Windows Azure Blob. Los nodos se podrían leer y actualizar el número de pedido, que proporciona un mecanismo de generación de número orden secuencial simple para su uso por múltiples nodos. Sin embargo, en este momento la contención para un sistema ocupado que requieren muchos nuevos números de pedido por segundo es probable que podría impedir la escalabilidad del sistema.
  3. Los identificadores únicos en cada nodo de la partición: Crear un contador en memoria ligero que genera números de orden único. A fin de garantizar su exclusividad en todos los nodos, cada nodo se asignaría un rango de números de pedido, como se muestra en de figura 1.

Figura 1 de números para cada nodo para asegurar que los identificadores únicos de asignar un rango de pedidos

Nodo Intervalo
A 0-1,000,000
B 1,000,001-2,000,000

Sin embargo, este enfoque conlleva una serie de preguntas. ¿Qué ocurre cuando un nodo agota un rango? ¿Qué sucede cuando cientos de nodos se agregan al sistema a la vez? ¿Qué ocurre si un nodo se bloquea y se sustituye por el tiempo de ejecución de Windows Azure con un nodo nuevo? Sería necesario estrechamente supervisar estos intervalos y tenga cuidado para asegurarse de que la configuración es correcta o daños en los datos se enfrentan los administradores.

En su lugar, se necesitaba un enfoque mucho más elegante, demuestra poca contención de una solución que no se requiere ninguna configuración por nodo, y garantiza la unicidad en todo momento. Para conseguirlo, creé un híbrido de las opciones segunda y terceros.

El concepto es relativamente sencillo: Utilice un pequeño archivo de texto en el objeto binario de almacenamiento para almacenar el último número de pedido. Cuando un nuevo número de pedido es necesario, un nodo puede tener acceso a este objeto binario, incremente el valor y escribir de nuevo para el almacenamiento de información. Por supuesto, hay una posibilidad razonable que otro nodo will have tiene acceso a los blob con la intención de la misma durante este proceso de incremento de lectura y escritura. Sin algún tipo de administración de concurrencia, los números de pedido de no ser únicos y los datos podrían estar dañados. Tradicionalmente, podría que hayan considerado la creación de un mecanismo de bloqueo impide que varios nodos funcionan de forma simultánea con el objeto binario. Sin embargo, los bloqueos son caros, y si el alta escalabilidad y rendimiento son guiar a los temas de la implementación, son que deben evitarse.

En su lugar, un enfoque con la concurrencia optimista es favorable. Con la concurrencia optimista, se admiten varios agentes interactuar con un recurso. Cuando un actor se recupera el recurso, el actor también se emite un símbolo (token) que indica la versión del recurso. Cuando realiza una actualización, puede incluirse el símbolo (token) para indicar qué versión del recurso se está modificando. Si el recurso ya se ha modificado por actor otro, a continuación, se producirá un error de la actualización y el actor original puede recuperar la versión más reciente y vuelva a intentarlo la actualización. La concurrencia optimista funciona bien siempre son pocas las posibilidades de conflictos en las actualizaciones. Se evita el costo y complejidad de un bloqueo y el recurso está protegido contra daños.

Imagine que, durante las horas punta, el sistema emite unas 100 nuevos números de pedido por segundo. Esto significa 100 solicitudes para actualizar el objeto binario de cada segundo, la causa de una probabilidad extremadamente alta de contención, lo que significaría el número de reintentos, aumenta la situación. Por lo tanto, para reducir la posibilidad de que esto suceda, decidí asignar números de pedido en intervalos.

Se ha creado una clase denominada la UniqueIdGenerator para encapsular este comportamiento. La clase quita un intervalo de números de pedido de almacenamiento blob incrementando el valor en fragmentos puede configurables. Si cada UniqueIdGenerator reservar números de pedido de 1000 a la vez, el objeto binario sólo se actualizará por término medio cada 10 segundos, lo que reduce las posibilidades de conflicto. Cada UniqueIdGenerator es libre para emitir su orden de 1.000 reservado que se va de números en, seguro de que ninguna otra instancia de la clase que señala al mismo objeto binario de recurso va a emitir el mismo número de pedido.

Para que este nuevo componente comprobable, una interfaz denominada IOptimisticSyncStore se ha especificado que independiente la UniqueIdGenerator del mecanismo de almacenamiento específica. Esto tiene una ventaja adicional: En el futuro, el componente podría utilizar un tipo de almacenamiento diferente en su caso. Ésta es la interfaz:

public interface IOptimisticSyncStore
{
  string GetData();
  bool TryOptimisticWrite(string data);
}

Como puede ver, es una interfaz simple con tan sólo dos métodos: uno para recuperar los datos y otro para actualizarlo, este último devuelva un valor de tipo Boolean que es false, indica que se ha producido un error de concurrencia optimista y el proceso se debe reintentar.

Una implementación de IOptimisticSyncStore que utiliza objetos binarios de almacenamiento está disponible en la descarga de código (obtener más información al final del artículo). La mayor parte, la implementación es sencilla;Sin embargo, conviene observar el TryOptimisticWrite se ha implementado el método de forma más detallada para comprender cómo la concurrencia optimista.

Es fácil de usar concurrencia optimista al actualizar los recursos de almacenamiento Blob Azure de Windows, gracias a las condiciones previas y etiquetas de la entidad (ETags). Una condición previa es una instrucción que declara un desarrollador debe ser true para una solicitud HTTP se realice correctamente. Si el servidor Web evalúa la instrucción en false, debe responder con un 412 de código de estado HTTP: “ Error de condición previa. ” ETags también forman parte de la especificación de HTTP y una versión concreta de un recurso, como, por ejemplo, un objeto binario de identificar. Si se cambia el objeto binario, la etiqueta ETag debe cambiar también, como se muestra aquí:

try
{

  _blobReference.UploadText(

    data,

    Encoding.Default,

    new BlobRequestOptions { 

    AccessCondition = AccessCondition.IfMatch(
    _blobReference.Properties.ETag) });

}

Para especificar una condición previa en el código, se utiliza el tipo de BlobRequestOptions y establezca la propiedad AccessCondition. Si esta condición de acceso no está satisfecho (por ejemplo, si el otro nodo actualiza el objeto binario en un breve período de tiempo desde que se recuperó), no coincide con el ETags y se iniciará un StorageClientException:

catch (StorageClientException exc)
{
  if (exc.StatusCode == HttpStatusCode.PreconditionFailed)
  {
    return false;
  }
  else
  {
    throw;
  }
}
return true;

La aplicación comprueba la excepción para el código de estado PreconditionFailed y devuelve false en este caso. Cualquier otro tipo de excepción es un error grave y se vuelve a producir para el registro de control y más en. No hay una excepción significa que la actualización realizó y el método devuelve true. De figura 2 muestra la lista completa de la clase UniqueIdGenerator.

La figura 2 de La clase de UniqueIdGenerator total

public class UniqueIdGenerator
{ 
    private readonly object _padLock = new object();
    private Int64 _lastId;
    private Int64 _upperLimit;
    private readonly int _rangeSize;
    private readonly int _maxRetries;
    private readonly IOptimisticSyncStore _optimisticSyncStore;

    public UniqueIdGenerator(
      IOptimisticSyncStore optimisticSyncStore,
      int rangeSize = 1000,
      int maxRetries = 25)
    {
      _rangeSize = rangeSize;
      _maxRetries = maxRetries;
      _optimisticSyncStore = optimisticSyncStore;

      UpdateFromSyncStore();
    }

    public Int64 NextId()
    {
      lock (_padLock)
      {
        if (_lastId == _upperLimit)
        {
          UpdateFromSyncStore();
        }
        return _lastId++;
      }
    }

    private void UpdateFromSyncStore()
    {
      int retryCount = 0;
      // maxRetries + 1 because the first run isn't a 're'try.
while (retryCount < _maxRetries + 1)
      {
        string data = _optimisticSyncStore.GetData();

        if (!Int64.TryParse(data, out _lastId))
        {
          throw new Exception(string.Format(
            "Data '{0}' in storage was corrupt and " +
            "could not be parsed as an Int64", data));
        }

        _upperLimit = _lastId + _rangeSize;

        if (_optimisticSyncStore.TryOptimisticWrite(
          _upperLimit.ToString()))
        {
          return;
        }

        retryCount++;
        // update failed, go back around the loop
      }

      throw new Exception(string.Format(
        "Failed to update the OptimisticSyncStore after {0} attempts",
        retryCount));
    }
}

El constructor toma tres parámetros. El primero es una implementación de IOptimisticSyncStore, por ejemplo, nuestra BlobOptimisticSyncStore se ha descrito anteriormente. El segundo parámetro es rangeSize, un valor entero que indica cómo debe ser el rango de números asignados desde el objeto binario. Cuanto mayor sea este intervalo, el menos posibilidades de conflicto. Sin embargo, los números más se perderá si este nodo se bloquee. El parámetro final es maxRetries, un valor entero que indica el número de veces que el generador se debe intentar actualizar el objeto binario de un error de concurrencia optimista. Más allá de este punto, se produce una excepción.

El método NextId es el miembro público únicamente de la clase UniqueIdGenerator y se utiliza para recuperar el siguiente número único. El cuerpo del método se sincroniza para asegurar que cualquier instancia de la clase es segura para subprocesos y se, por ejemplo, puede compartir entre todos los subprocesos que se está ejecutando la aplicación Web. Una si la instrucción se comprueba si el generador ha alcanzado el límite superior de su asignación de intervalo y, si es así, llama a UpdateFromSyncStore para obtener un nuevo intervalo de almacenamiento de información blob.

El método UpdateFromSyncStore es la parte final, pero lo más interesante de la clase. La implementación de IOptimisticSyncStore se utiliza para recuperar el límite superior de la asignación anterior emitido. El valor se incrementa en tamaño del intervalo del generador, y esto se devuelven al almacenamiento. Un simple bucle “ while ” incluye el cuerpo para asegurarse de que el número de reintentos adecuado tiene lugar si TryOptimisticWrite devuelve false.

El fragmento de código siguiente muestra un UniqueIdGenerator construye, utilizando un BlobOptimisticSyncStore con un archivo denominado “ ordernumber.dat ” en un contenedor llamado “ uniqueids ” (Nota: contenedores de almacenamiento de objetos binarios deben tener nombres en minúsculas):

IOptimisticSyncStore storage = new BlobOptimisticSyncStore(
  CloudStorageAccount.DevelopmentStorageAccount, 
  "uniqueids", 
  "ordernumber.dat");
UniqueIdGenerator
  generator = new UniqueIdGenerator(storage, 1000, 10);

Esta instancia quita de 1.000 identificadores de la gama central y volverá a intentar 10 veces en el caso de un error de concurrencia optimista antes de iniciar una excepción.

El uso de la UniqueIdGenerator es aún más sencillo. Siempre que necesite un nuevo número de orden único, basta con llamar a NextId:

Int64 orderId = generator.NextId();

El ejemplo de código muestra una función de trabajo de Azure de Windows que utiliza varios subprocesos para asignar números únicos de la orden de forma rápida y escribirlos en una base de datos SQL. El uso de SQL en esta instancia es simplemente demostrar que cada número de pedido es único, cualquier infracción de esta podría producir una infracción de clave principal e inicia una excepción.

La ventaja de este enfoque, diferente de crear el objeto binario y establecer su valor en 0 justo al principio del período de duración de la aplicación, es que no es necesario del Administrador de sistemas, esfuerzo. El UniqueIdGenerator cuidadosamente administra la asignación de identificadores en función de la configuración, se recupera correctamente en el caso de un error y escala de sin esfuerzo incluso en los entornos más elástico.

Escenario 2: Suelte los reconocidas.

Otro requisito interesante que supone la aplicación era la necesidad de procesar rápidamente grandes cantidades de datos después de un evento especificado que se produce en un tiempo de aproximadamente conocido. Debido a la naturaleza de la transformación, no se puede comenzar el trabajo en cualquiera de los datos hasta después de este evento.

Funciones de trabajo son una elección obvia en este escenario, y Would have sido posible hacer simplemente Azure de Windows para proporcionar el número necesario de funciones de trabajo en respuesta al evento mencionadas anteriormente. Sin embargo, el aprovisionamiento de nuevas funciones puede tardar hasta 30 minutos, y era de velocidad de la esencia de este escenario. Por lo tanto, se decidió que se haría hidratadas las funciones de antemano, pero en un estado de pausa hasta que libere un administrador, llama a este “ Release los reconocidas ”! Se consideraban que dos enfoques posibles y revisaré cada vez.

Debe tenerse en cuenta que, debido a que Windows se atribuyen funciones de trabajo Azure en función del tiempo que se implementen (no en la forma activa que utilizan la CPU), este enfoque podría costo, comparado más que simplemente crear las funciones de trabajo en respuesta al evento. Sin embargo, el cliente estaba claro que esta inversión no merezca la pena asegurarse de que se puede comenzar el procesamiento tan rápidamente como sea posible.

Método I: Sondeo

El primer enfoque, se muestra en figura 3, tenía cada nodo sondear un indicador de estado central a intervalos regulares (de nuevo, se almacenan en un objeto binario de Windows Azure) para determinar si aún se puede iniciar el trabajo.

image: Nodes Polling a Central Status Flag

La figura 3 de sondeo de los nodos de un indicador de estado central

Finaliza la pausa los nodos, una aplicación de cliente sólo tenía que establezca este indicador como true y con el sondeo de las siguientes, se debería liberar todos los nodos. La principal desventaja de este enfoque es la latencia, potencialmente, tan grande como el intervalo de sondeo. Por otra parte, se trata de un mecanismo muy sencillo y confiable para implementar.

Este diseño se muestra la clase PollingRelease disponible en el ejemplo de código. Para admitir la capacidad de prueba, el mecanismo de almacenamiento de indicador se abstrae detrás de una interfaz en la misma manera que para la clase UniqueIdGenerator. La interfaz IGlobalFlag y la implementación correspondiente para el almacenamiento de información blob que se muestran en figura 4.

La figura 4 de la interfaz IGlobalFlag e implementación para el almacenamiento de Blob

public interface IGlobalFlag
{
  bool GetFlag();
  void SetFlag(bool status);
}

public class BlobGlobalFlag : IGlobalFlag
{
  private readonly string _token = "Set";
  private readonly CloudBlob _blobReference;
  public BlobGlobalFlag(CloudStorageAccount account, string container,    
    string address)
  {
    var blobClient = account.CreateCloudBlobClient();
    var blobContainer =   
      blobClient.GetContainerReference(container.ToLower());
    _blobReference = blobContainer.GetBlobReference(address);
  }

  public void SetFlag(bool status)
  {
    if (status)
   {
      _blobReference.UploadText(_token);
    }
    else
    {
      _blobReference.DeleteIfExists();
    }
  }

  public bool GetFlag()
  {
    try
    {
      _blobReference.DownloadText();
      return true;
    }
    catch (StorageClientException exc)
    {
      if (exc.StatusCode == System.Net.HttpStatusCode.NotFound)
      {
        return false;
      }
      throw;
    }
  }
}

Observe que en este ejemplo, la mera existencia de un archivo de almacenamiento de información blob indica es true, independientemente de lo que el contenido.

La propia clase PollingRelease es sencilla, como se muestra en de figura 5, con un método público que llama a esperar.

La figura 5 de La clase PollingRelease

public class PollingRelease 
{
  private readonly IGlobalFlag _globalFlag;
  private readonly int _intervalMilliseconds;

  public PollingRelease(IGlobalFlag globalFlag, 
    int intervalMilliseconds)
  {
    _globalFlag = globalFlag;
    _intervalMilliseconds = intervalMilliseconds;
  }

  public void Wait()
  {
    while (!_globalFlag.GetFlag())
    {
      Thread.Sleep(_intervalMilliseconds);
    }
  }
}

Este método bloquea cualquier llamador siempre que la implementación de IGlobalFlag indica que su estado es false. El fragmento de código siguiente muestra la clase PollingRelease en uso:

BlobGlobalFlag globalFlag = new BlobGlobalFlag(
  CloudStorageAccount.DevelopmentStorageAccount,
  "globalflags",
  "start-order-processing.dat");
PollingRelease pollingRelease = new PollingRelease(globalFlag, 2500);
pollingRelease.Wait();

Se crea una instancia de la BlobGlobalFlag que señala a un contenedor denominado “ globalflags. ” La clase PollingRelease sondeará cada 2,5 segundos para la presencia de un archivo denominado “ inicio-orden-processing.dat ”cualquier llamada al método Wait, se bloqueará hasta que este archivo existe.

Enfoque II: La escucha

El segundo enfoque utiliza el bus de servicios de Windows Azure AppFabric al mismo tiempo, comunicarse con todas las funciones de trabajo directamente y liberarlos (consulte de figura 6).

image: Using the Windows Azure AppFabric Service Bus to Simultaneously Communicate with All Worker Roles

La figura 6 de utilización del bus de Azure de AppFabric de servicios de Windows simultáneamente comunicarse con todos los roles de trabajo

El bus de servicios es un servicio de mensajería y la conectividad a gran escala, que también se basa en Windows Azure. Facilita la comunicación segura entre los distintos componentes de una aplicación distribuida. El bus de servicios proporciona una solución ideal para conectar dos aplicaciones que se haría en caso contrario, tener dificultades para comunicarse, debido a su ubicación detrás de un límite de (NAT) de la traducción de direcciones de red o una dirección IP cambia con frecuencia, por ejemplo. Queda fuera del alcance de este artículo para ofrecer una introducción detallada del bus de servicios de Windows Azure AppFabric, pero un excelente tutorial está disponible en MSDN en msdn.microsoft.com/library/ee706736 de .

Para demostrar este enfoque, se crea una clase que se llama ListeningRelease que, como PollingRelease, dispone de un método público denominado Wait. Este método conecta con el bus de servicios y usa un ManualResetEvent para bloquear el subproceso hasta que se reciba una señal:

public void Wait()
{
  using (ConnectToServiceBus())
  {
    _manualResetEvent.WaitOne();
  }
}

El método ConnectToServiceBus completo aparece en figura 7. Utiliza tipos de los ensamblados de System.ServiceModel y Microsoft.ServiceBus para exponer una clase denominada UnleashService para la nube a través del bus de servicios de Windows Azure AppFabric, se muestra en figura 8.

La figura 7 del Método ConnectToServiceBus

private IDisposable ConnectToServiceBus()
{
  Uri address = ServiceBusEnvironment.CreateServiceUri("sb",  
    _serviceNamespace, _servicePath);
  TransportClientEndpointBehavior sharedSecretServiceBusCredential =  
    new TransportClientEndpointBehavior();
  sharedSecretServiceBusCredential.CredentialType =  
    TransportClientCredentialType.SharedSecret;
  sharedSecretServiceBusCredential.Credentials.SharedSecret.
IssuerName = _issuerName;
  sharedSecretServiceBusCredential.Credentials.SharedSecret.
IssuerSecret = _issuerSecret;

  // Create the single instance service, which raises an event
  // when the signal is received.
UnleashService unleashService = new UnleashService();
  unleashService.Unleashed += new  
    EventHandler(unleashService_Unleashed);

  // Create the service host reading the configuration.
ServiceHost host = new ServiceHost(unleashService, address);

  IEndpointBehavior serviceRegistrySettings = 
    new ServiceRegistrySettings(DiscoveryType.Public);

  foreach (ServiceEndpoint endpoint in host.Description.Endpoints)
  {
    endpoint.Behaviors.Add(serviceRegistrySettings);
    endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
  }

  host.Open();

  return host;
}

Figura 8 de la clase UnleashService

[ServiceBehavior(InstanceContextMode= InstanceContextMode.Single)]
public class UnleashService : IUnleashContract
{
  public void Unleash()
  {
    OnUnleashed();
  }

  protected virtual void OnUnleashed()
  {
    EventHandler temp = Unleashed;
    if (temp != null)
    {
      temp(this, EventArgs.Empty);
    }
  }

  public event EventHandler Unleashed;
}

El UnleashService está alojado por Windows Communication Foundation (WCF) como una sola instancia y implementa el contrato IUnleashService, que tiene un método: Dé rienda suelta. ListeningRelease detecta una llamada a este método a través del evento Unleashed mostrado anteriormente. Cuando la clase ListeningRelease observa este evento, se establece el ManualResetEvent que está bloqueando las llamadas en espera y se liberan todos los subprocesos bloqueados.

En la configuración del servicio, se ha utilizado el NetEventRelayBinding, que admite la multidifusión a través del bus de servicios, lo que permite que a cualquier número de publicadores y suscriptores para comunicarse a través de un único extremo. La naturaleza de esta difusión de comunicación requiere que todas las operaciones son unidireccionales, como se muestra la interfaz IUnleashContract:

[ServiceContract]
public interface IUnleashContract
{
  [OperationContract(IsOneWay=true)]
  void Unleash();
}

El punto final está protegido con una clave compartida (nombre de usuario y una contraseña compleja). Con estos detalles, cualquier cliente de acceso a Internet se ha podido invocar el método Unleash, incluidos, por ejemplo, en el ejemplo de la consola de administrador (consulte de figura 9).

image: The Administrator Console

La figura 9 de la consola de administrador

Aunque el enfoque ListeningRelease hace directamente con la latencia inherente de la clase PollingRelease, sigue habiendo cierta latencia que afrontar. Sin embargo, el principal inconveniente del enfoque de escucha es su naturaleza sin estado, de modo que cualquier nodo proporcionado después de la señal de la versión que se haya transmitido no ve este suceso y debería permanecer en pausa. Por supuesto, puede ser una solución obvia combinar el bus de servicios y el indicador global del objeto binario de almacenamiento, pero dejamos como ejercicio para el lector.

Ejemplo de código

La solución de ejemplo que lo acompaña está disponible en code.msdn.microsoft.com/mag201011Sync de e incluye un archivo Léame que se enumera los requisitos previos y que incluye las instrucciones de instalación y configuración. El ejemplo utiliza el ListeningRelease, PollingRelease y UniqueIdGenerator en una única función de trabajo.

Trenza de Josh   es un jefe de desarrollo de la aplicación principal con el soporte técnico Premier de equipo de desarrolladores en el Reino Unido y se puede encontrar blogs en thejoyofcode.com de .

Gracias a los siguientes expertos técnicos de este artículo: David Goon, Morgan Skinnery de Wade Wegner