Objetivo
Na parte 7 dessa série vimos uma implementação baseada em MSMQ que ficou muito atrás da implementação em Websphere MQ e eu tinha me comprometido a revisá-la. O objetivo deste post é apresentar essa revisão.
A princípio imaginei que o resultado ruim estava relacionado a filas transacionais, mas na prática percebi que o problema estava principalmente relacionado ao tratamento do recebimento da fila de forma assíncrona.
Melhorias realizadas
Realizei algumas melhorias pequenas no código, substituindo o loop deselegante na thread principal por um ManualResetEvent e outras melhorias menores, mas o ponto chave estava no tratamento do evento “ReceiveCompleted” da fila.
Criei uma Queue e uma segunda thread para tratar de forma paralela, não obstruindo o caminho do MQ com código de processamento e deixando o canal de recepção de mensagens livre para dar mais vazão à fila de entrada. Ficou assim:
private void inQueue_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e) { lock (messageInputQueue) { messageInputQueue.Enqueue(e.Message); enqueueCount++; Log.LogMessage("Enqueued " + enqueueCount.ToString() + " messages"); } if (enqueueCount < TotalBatches) inputQueue.BeginReceive(); }
messageInputQueue trata-se da Queue a que me referi. É utilizado um “lock” para evitar concorrência entre a thread que empilha e a que desempilha as mensagens.
Este é o código que trata o processamento das mensagens, executado através de uma Task:
private void ProcessInputQueue() { while (true) { Message msg = null; lock (messageInputQueue) { if (messageInputQueue.Count > 0) msg = messageInputQueue.Dequeue(); } if (msg == null) { Thread.Sleep(50); continue; } StreamUtil.ImportarStream(ConnString, msg.BodyStream); Log.LogMessage("Processed message " + messageCount.ToString()); messageCount--; if (messageCount <= 0) break; } processingDone.Set(); }
Resultados
Abaixo segue os resultados completos inserindo também as execuções do MSMQ com filas transacionais e não-transacionais:
Como os resultados mostram, a diferença do Websphere MQ para o MSMQ não foi significativa, mas as diferenças entre a implementação anterior em MSMQ para a nova é absurdamente grande (praticamente o dobro!).
Código fonte
O código fonte completo está atualizado no Git Hub: https://github.com/ericlemes/IntegrationTests
Post muito bom, parabéns! Seria interessante um post semelhante utilizando WCF + ActiveMQ.
Abraço.
Cristian,
Que bom que gostou. Vou colocar no meu roadmap, mas não prometo nada. Acho que o Rabbit MQ vem antes, depois algumas brincadeiras com Service Bus.
Acho que vou botar um link de “donate” no blog pra ver se vem algum incentivo!
Abraço,
Eric