VENDAS: 1-800-867-1389

Enviar mensagens de maneira assíncrona

Atualizado: março de 2014

Para aproveitar os recursos avançados de desempenho do Microsoft Azure Service Bus como envio em lote do lado do cliente, você deve sempre considerar a utilização do modelo de programação assíncrona ao implementar uma solução de mensagens utilizando a API de mensagens orientadas gerenciadas pelo .NET. O padrão de mensagens assíncronas permitirá que você construa soluções que geralmente conseguem evitar sobrecarga de operações E/S como envio e recebimento de mensagens.

Ao invocar um método da API de maneira assíncrona, o controle retorna imediatamente ao seu código e sua aplicação continua em execução enquanto a operação assíncrona é executada independentemente. Sua aplicação pode monitorar a operação assíncrona ou ser notificada através de um retorno de chamada quando a operação for finalizada. Então, sua aplicação pode obter e processar os resultados.

É importante observar que ao invocar operações síncronas, por exemplo os métodos Send ou Receive na classe QueueClient (ou outros métodos síncronos fornecidos por Service Bus API de mensagens orientadas), internamente o código da API flui através das versões assíncronas dos métodos respectivos, embora de modo a bloquear. Porém, utilizar as versões síncronas destes métodos pode não renderizar o espetro completo dos benefícios relacionados ao desempenho que você pode esperar ao chamar as versões assíncronas diretamente. Isto é particularmente evidente quando enviar ou receber mensagens múltiplas e desejar desempenhar outros processamentos enquanto as operações de mensagens estão sendo executadas.

noteObservação
Um objeto BrokeredMessage representa uma mensagem, e é fornecido com o propósito de transmissão de dados pelo fio. Assim que um objeto BrokeredMessage for enviado à uma fila ou tópico, é consumido pela pilha de mensagens subjacente e não pode ser reutilizado para outras operações. Isto acontece devido ao fato de que, após a leitura do corpo da mensagem, o fluxo que projeta a mensagem não pode ser rebobinado. Você deve reter os dados utilizados para a construção de uma instância BrokeredMessage até que possa afirmar o sucesso da operação de mensagens de maneira confiável. Se uma operação de mensagens com falha exige uma nova tentativa, você deve construir uma nova instância BrokeredMessage utilizando esta fonte de dados.

O seguinte trecho de código demonstra como enviar mensagens múltiplas de maneira assíncrona (e confiável) mantendo a ordem na qual as mensagens estão sendo enviadas:

// This sample assumes that a queue client is declared and initialized earlier.

// Declare the list of messages that will be sent.
List<XElement> messages = new List<XElement>();

// Populate the list of messages.
for (int i = 0; i < msgCount; i++)
{
    messages.Add(XDocument.Load(new StringReader(String.Format(@"<root><msg num=""{0}""/></root>", i))).Root);
}

// Declare a list in which sent messages will be tracked.
var sentMessages = new List<XElement>();

// Declare a wait object that will be used for synchronization.
var waitObject = new ManualResetEvent(false);

// Declare a timeout value during which the messages are expected to be sent.
var sentTimeout = TimeSpan.FromMinutes(10);

// Declare and initialize an action that will be calling the asynchronous messaging operation.
Action<XElement> sendAction = null;
sendAction = ((payload) =>
{
    // 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.
            BrokeredMessage msg = new BrokeredMessage(payload, new DataContractSerializer(typeof(XElement)));

            // Send the message asynchronously.
            queueClient.BeginSend(msg, cb, Tuple.Create<XElement, BrokeredMessage>(payload, msg));
        },
        (ar) =>
        {
            // Obtain the state object containing the brokered message being sent.
            var state = ar.AsyncState as Tuple<XElement, BrokeredMessage>;

            try
            {
                // Complete the asynchronous operation. This may throw an exception that will be handled internally by the retry policy.
                queueClient.EndSend(ar);

                // Track sent messages so that we can determine what was actually sent.
                sentMessages.Add(state.Item1);

                // Get the next message to be sent.
                var nextMessage = sentMessages.Count < messages.Count ? messages[sentMessages.Count] : null;

                // Make sure we actually have another message to be sent.
                if (nextMessage != null)
                {
                    // If so, call the Send action again to send the next message.
                    sendAction(nextMessage);
                }
                else
                {
                    // Otherwise, signal the end of the messaging operation.
                    waitObject.Set();
                }
            }
            finally
            {
                // Ensure that any resources allocated by a BrokeredMessage instance are released.
                if (state != null & state.Item2 != null)
                {
                    state.Item2.Dispose();
                }
            }
        },
        (ex) =>
        {
            // Always log exceptions.
            Trace.TraceError(ex.Message);
        }
    );
});

// Start with sending the first message.
sendAction(messages[0]);

// Perform other processing while the messages are being sent.
// ...

// Wait until the messaging operations are completed.
bool completed = waitObject.WaitOne(sentTimeout);
waitObject.Dispose();

if (completed && sentMessages.Count == messages.Count)
{
    // Handle successful completion.
}
else
{
    // Handle timeout condition (or a failure to send all messages).
}

Sempre que possível, evite a execução de operações de mensagens em paralelo utilizando agendamento padrão e trabalhe com algoritmos de particionamento fornecidos pela Biblioteca paralela de tarefas (TPL) e LINQ paralelo (PLINQ). O básico do TPL Framework é mais indicado para adicionar paralelismo e simultaneidade para aplicações principalmente de uma perspectiva de operação vinculada à computação. O uso de TPL "como é" para melhorar o desempenho de código associado à E/S como chamadas de rede e operações de mensagens pode não produzir as melhorias esperadas. A melhor maneira de aproveitar a TPL para oferecer suporte à operações assíncronas é através da utilização de padrões avançados de TPL em conformidade com o modelo de programação assíncrona.

Isso foi útil para você?
(1500 caracteres restantes)
Agradecemos os seus comentários
Mostrar:
© 2014 Microsoft