Exportar (0) Imprimir
Expandir todo

Controlar errores de comunicación transitorios

Actualizado: marzo de 2014

Para mejorar la confiabilidad de una solución que usa la API administrada de mensajería negociada de Microsoft Azure Service Bus .NET, se recomienda que adopte un enfoque coherente para controlar los errores transitorios e intermitentes que pueden aparecer cuando la solución se comunica con la infraestructura de servicio de mensajería de publicación y suscripción y puesta en cola basada en la nube y multiempresa proporcionada por Service Bus.

Para mejorar la confiabilidad de una solución que usa la API administrada de mensajería negociada de Service Bus .NET, se recomienda que adopte un enfoque coherente para controlar los errores transitorios e intermitentes que pueden aparecer cuando la solución se comunica con la infraestructura de servicio de mensajería de publicación y suscripción y puesta en cola basada en la nube y multiempresa proporcionada por Service Bus.

Al considerar una técnica determinada para detectar las condiciones transitorias, quizá prefiera volver a usar las soluciones técnicas existentes como el Marco para la administración de errores transitorios o crear su propia solución. En los dos casos, tendrá que asegurarse de que solo un subconjunto de las excepciones de comunicación se trata como transitorio antes de intentar recuperarse de los errores respectivos.

La tabla que se muestra aquí proporciona una lista de excepciones que se pueden compensar mediante la implementación de la lógica de reintento:

 

Tipo de excepción

Recomendación

ServerBusyException

Esta excepción puede ser debida a un error intermitente en la infraestructura de servicio de mensajería de Service Bus que no puede procesar una solicitud debido a condiciones de carga anómalas en un momento dado. El cliente puede probar reintentar con un retraso. Sería preferible un retraso de espera para impedir agregar una presión innecesaria al servidor.

MessagingCommunicationException

Esta excepción señala un error de comunicación que se puede manifestar en sí cuando no se puede establecer correctamente una conexión del cliente de mensajería con la infraestructura de Service Bus. En la mayoría de los casos, si existe una conectividad de red, este error se puede tratar como transitorio. El cliente puede probar reintentar la operación que ha producido este tipo de excepción. Se recomienda también que compruebe si el servicio de resolución de nombres de dominio (DNS) está operativo porque este error puede indicar que el nombre de host de destino no se puede resolver.

TimeoutException

Esta excepción indica que la infraestructura de servicio de mensajería de Service Bus no ha respondido a la operación solicitada en el tiempo especificado que el valor de OperationTimeout controla. La operación solicitada puede todavía haberse completado; sin embargo, debido a retrasos de red u otros retrasos de infraestructura, puede que la respuesta no haya llegado al cliente puntualmente. La compensación de este tipo de excepciones se debe realizar con precaución. Si se ha entregado un mensaje a una cola pero la respuesta ha excedido el tiempo de espera, volver a enviar el mensaje inicial provocará la duplicación.

Para obtener información más detallada sobre los distintos tipos de excepciones que puede notificar la API de mensajería de Service Bus, vea el tema Excepciones de mensajería.

noteNota
Al controlar los errores de comunicación transitorios, tenga cuidado de las excepciones transitorias enmascaradas por excepciones externas de un tipo distinto. Por ejemplo, se puede devolver al autor de llamada un tiempo de espera excedido en la forma de un error de comunicación que oculta el tiempo de espera excedido inicial como una excepción interna. Se recomienda por tanto que inspeccione todas las excepciones internas de un objeto de excepción determinado de forma recursiva para poder detectar de forma confiable los errores de comunicación transitorios. La clase ServiceBusTransientErrorDetectionStrategy del Marco para la administración de errores transitorios proporciona un ejemplo de cómo puede hacer esto.

En el fragmento de código siguiente se muestra cómo enviar de forma asincrónica un mensaje a un tema de Service Bus a la vez que se asegura de que todos los errores transitorios conocidos se compensarán mediante un reintento. Tenga en cuenta que este ejemplo de código mantiene una dependencia del Marco para la administración de errores transitorios.

var credentials = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerSecret);
var address = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, String.Empty);
var messagingFactory = MessagingFactory.Create(address, credentials);
var topicClient = messagingFactory.CreateTopicClient(topicPath);
var retryPolicy = new RetryPolicy<ServiceBusTransientErrorDetectionStrategy>(RetryPolicy.DefaultClientRetryCount);

// Create an instance of the object that represents message payload.
var payload = XDocument.Load("InventoryFile.xml");

// Declare a BrokeredMessage instance outside so that it can be reused across all 3 delegates below.
BrokeredMessage msg = null;

// Use a retry policy to execute the Send action in an asynchronous and reliable fashion.
retryPolicy.ExecuteAction
(
    (cb) =>
    {
        // A new BrokeredMessage instance must be created each time we send it. Reusing the original BrokeredMessage instance may not 
        // work as the state of its BodyStream cannot be guaranteed to be readable from the beginning.
        msg = new BrokeredMessage(payload.Root, new DataContractSerializer(typeof(XElement)));

        // Send the event asynchronously.
        topicClient.BeginSend(msg, cb, null);
    },
    (ar) =>
    {
        try
        {
            // Complete the asynchronous operation. 
            // This may throw an exception that will be handled internally by the retry policy.
            topicClient.EndSend(ar);
        }
        finally
        {
            // Ensure that any resources allocated by a BrokeredMessage instance are released.
            if (msg != null)
            {
                msg.Dispose();
                msg = null;
            }
        }
    },
    (ex) =>
    {
        // Always dispose the BrokeredMessage instance even if the send 
        // operation has completed unsuccessfully.
        if (msg != null)
        {
            msg.Dispose();
            msg = null;
        }

        // Always log exceptions.
        Trace.TraceError(ex.Message);
    }
);

En el ejemplo de código siguiente se muestra cómo crear de forma confiable un tema nuevo o cómo recuperar un tema de Service Bus existente. En este código se mantiene también una dependencia del Marco para la administración de errores transitorios que reintentará automáticamente la operación de administración correspondiente si no se puede completar correctamente debido a errores de conectividad intermitentes u otros tipos de condiciones transitorias:

public TopicDescription GetOrCreateTopic(string issuerName, string issuerSecret, string serviceNamespace, string topicName)
{
    // Must validate all input parameters here. Use Code Contracts or build your own validation.
    var credentials = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerSecret);
    var address = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, String.Empty);
    var nsManager = new NamespaceManager(address, credentials);
    var retryPolicy = new RetryPolicy<ServiceBusTransientErrorDetectionStrategy>(RetryPolicy.DefaultClientRetryCount);

    TopicDescription topic = null;
    bool createNew = false;

    try
    {
        // First, let's see if a topic with the specified name already exists.
        topic = retryPolicy.ExecuteAction<TopicDescription>(() => { return nsManager.GetTopic(topicName); });

        createNew = (topic == null);
    }
    catch (MessagingEntityNotFoundException)
    {
        // Looks like the topic does not exist. We should create a new one.
        createNew = true;
    }

    // If a topic with the specified name doesn't exist, it will be auto-created.
    if (createNew)
    {
        try
        {
            var newTopic = new TopicDescription(topicName);

            topic = retryPolicy.ExecuteAction<TopicDescription>(() => { return nsManager.CreateTopic(newTopic); });
        }
        catch (MessagingEntityAlreadyExistsException)
        {
            // A topic under the same name was already created by someone else, 
            // perhaps by another instance. Let's just use it.
            topic = retryPolicy.ExecuteAction<TopicDescription>(() => { return nsManager.GetTopic(topicName); });
        }
    }

    return topic;
}

En resumen, recomendamos que evalúe la probabilidad de que se produzca un error y determine la viabilidad de agregar resistencia adicional. Prácticamente todas las operaciones de mensajería pueden estar sujetas a condiciones transitorias. Al llamar a la API de mensajería negociada, se recomienda, por lo tanto, que tome las medidas adecuadas para proporcionar siempre la recuperación de problemas intermitentes.

Mostrar:
© 2014 Microsoft