Como encontrar uma mensagem na fila do MSMQ?
31/05/2017
0
Cenário:
Aqui na empresa temos 20 PDV's e todos fazem comunicação com SAT, porém não temos 1 SAT para cada PDV, então foi desenvolvida uma aplicação que distribui as chamadas dos PDV's para os equipamentos SAT disponíveis na loja, uma espécie de "roteador". Quando um PDV fecha a venda e manda os dados para o SAT, as chamadas são enfileiradas no MSMQ, que serão lidas por uma aplicação consumidora dessas mensagens e no final serão colocadas em uma outra fila de "mensagens já processadas", onde cada PDV fará a leitura dos registros e quando encontrar a mensagem que corresponde ao seu pedido original, tira a mensagem da fila de "mensagens já processadas".
Problema:
Acho muito demorado essa última parte, pois o PDV tem que ler a fila inteira pra achar o que precisa, só que se a fila for muito grande, pode haver muita demora para o cliente pagante.
Pergunta:
Será que o vocês poderiam me aconselhar em como localizar a mensagem que o PDV precisa de maneira rápida?
Segue o exemplo de como eu faço a busca.
Fazendo uma simulação de 20 PDV's acessando, ele retorna a mensagem em torno de 16s, o que acaba sendo muita coisa. Em alguns momentos a consulta que usa Parallel dá a seguinte exception: "A mensagem para a qual o cursor está apontando atualmente foi removida da fila por outro processo ou por outra chamada a Receive sem o uso desse cursor."
Aqui na empresa temos 20 PDV's e todos fazem comunicação com SAT, porém não temos 1 SAT para cada PDV, então foi desenvolvida uma aplicação que distribui as chamadas dos PDV's para os equipamentos SAT disponíveis na loja, uma espécie de "roteador". Quando um PDV fecha a venda e manda os dados para o SAT, as chamadas são enfileiradas no MSMQ, que serão lidas por uma aplicação consumidora dessas mensagens e no final serão colocadas em uma outra fila de "mensagens já processadas", onde cada PDV fará a leitura dos registros e quando encontrar a mensagem que corresponde ao seu pedido original, tira a mensagem da fila de "mensagens já processadas".
Problema:
Acho muito demorado essa última parte, pois o PDV tem que ler a fila inteira pra achar o que precisa, só que se a fila for muito grande, pode haver muita demora para o cliente pagante.
Pergunta:
Será que o vocês poderiam me aconselhar em como localizar a mensagem que o PDV precisa de maneira rápida?
Segue o exemplo de como eu faço a busca.
MessageQueueTransaction transaction = new MessageQueueTransaction(); try { transaction.Begin(); //As mensagens da fila estão identificadas por uma label e eu uso essa informação para buscar a mensagem na fila string label = CreateLabelForMessage(intLojaID, intSatVendaId); Message message = _messageQueue.GetAllMessages().AsParallel().FirstOrDefault(x => x.Label == label); if (message == null) return; _messageQueue.ReceiveById(message.Id, transaction); transaction.Commit(); SAT_VendaDO objSatVenda = (SAT_VendaDO)message.Body; dtoSatVenda.Codigo_Retorno = objSatVenda.Codigo_Retorno; dtoSatVenda.Retorno_Motivo = objSatVenda.Retorno_Motivo; dtoSatVenda.XML = objSatVenda.XML; dtoSatVenda.Data_Retorno = objSatVenda.Data_Retorno; dtoSatVenda.Chave_Consulta = objSatVenda.Chave_Consulta; dtoSatVenda.Numero_Documento = objSatVenda.Numero_Documento; dtoSatVenda.Enum_Status_ID = objSatVenda.Enum_Status_ID; dtoSatVenda.SAT_ID = objSatVenda.SAT_ID; dtoSatVenda.SAT_Venda_ID = objSatVenda.SAT_Venda_ID; } catch (Exception ex) { transaction.Abort(); } finally { _messageQueue.Close(); } return;
Fazendo uma simulação de 20 PDV's acessando, ele retorna a mensagem em torno de 16s, o que acaba sendo muita coisa. Em alguns momentos a consulta que usa Parallel dá a seguinte exception: "A mensagem para a qual o cursor está apontando atualmente foi removida da fila por outro processo ou por outra chamada a Receive sem o uso desse cursor."
Jefferson Cruz
Curtir tópico
+ 0
Responder
Post mais votado
08/06/2017
Opa Jefferson, vamos lá. Primeiro, o problema de utilizar o paralelismo nessa consulta é justamente o erro que tu tens recebido eventualmente. Conforme o número de buscas paralelas aumenta, esses erros também irão. Sem contar que podem existir inserções enquanto há uma busca, o que complica ainda mais as coisas.
Sobre a implementação, me parece uma questão de trocar a estrutura de dados, abandonando o MSMQ. Como o grande gargalo é para o cliente, trocar a fila por um estrutura indexada é o caminho. Acho que um dicionário de dados seria o ideal, utilizando como "key" um identificador único que os PDV's conhecem. Assim, a busca teria complexidade de O(1). Claro que levaria mais tempo para armazenamento, sem contar a implementação do dicionário, mas no medio/longo prazo tu terias ganho, e nem sei se isso seria possível na tua estrutura.
O paralelismo também é um caminho, mas a natureza do sistema dificulta a implementação correta, e o ganho certamente não seria tão grande.
Sobre a implementação, me parece uma questão de trocar a estrutura de dados, abandonando o MSMQ. Como o grande gargalo é para o cliente, trocar a fila por um estrutura indexada é o caminho. Acho que um dicionário de dados seria o ideal, utilizando como "key" um identificador único que os PDV's conhecem. Assim, a busca teria complexidade de O(1). Claro que levaria mais tempo para armazenamento, sem contar a implementação do dicionário, mas no medio/longo prazo tu terias ganho, e nem sei se isso seria possível na tua estrutura.
O paralelismo também é um caminho, mas a natureza do sistema dificulta a implementação correta, e o ganho certamente não seria tão grande.
Henrique Gasparotto
Responder
Mais Posts
19/06/2017
Jefferson Cruz
Fiz alguns ajustes no serviço e toda vez que uma mensagem é processada eu guardo ela no MSMQ e também na memória, assim a consulta passa a ser na memória pesquisando dentro de um dicionário pelo numero do pedido, como você citou. Consegui diminuir o tempo de pesquisa de 16s para até 5s.
Responder
Clique aqui para fazer login e interagir na Comunidade :)