Conceito

Antes de mais nada, uma explicação conceitual sobre idempotência:

Em matemática e ciência da computação, a idempotência é a propriedade que algumas operações têm de poderem ser aplicadas várias vezes sem que o valor do resultado se altere após a aplicação inicial.
Fonte: http://pt.wikipedia.org/wiki/Idempot%C3%AAncia

Uma outra forma de dizer a mesma coisa: ““Uma operação é considerada idempotente se , não importa quantas vezes ela é executada, o resultado será o mesmo.”
Fonte: http://cloudswave.com/blog/simple-yet-powerful-concepts-about-the-cloud/

Cenário

Um cenário onde o conceito é aplicado é quando trabalhamos com fila de mensagens.

Observação: este cenário leva em consideração uma fila sem utilizar o padrão publish/subscribe. No caso do Azure, é possível o pubsub com o Azure Service Bus.

Em se tratando de uma fila de mensagens básica como do Azure Queue Service, imaginemos o seguinte cenário:

  1. Um website de comercio eletrônico, front-end executando em uma web role, coloca uma mensagem de fechamento de pedido na fila de processamento, em resposta a uma ação do usuário que está comprando algum produto no site.
  2. No back-end, uma worker role fica “escutando” a fila de mensagens para processa-las assim que chegar a mensagem. No caso da mensagem estar no Azure Queue Service, assim que a mensagem é obtida, ela é “escondida” por alguns instantes e caso não seja excluída definitivamente ela voltará para a fila para uma nova tentativa de execução. Entre a obtenção da mensagem e a exclusão dela é que ocorre a execução da regra de negócio, neste cenário, o processamento do pedido do cliente.

Pois bem, neste simples cenário temos uma fragilidade no aplicativo, onde coisas ruins podem acontecer, e segundo nosso amigo Murphy (Lei de Murphy), se algo pode dar errado, dará errado da pior maneira, no pior momento e de modo a causar o maior estrago possível. Costumo não duvidar dele, então é melhor prepararmos o aplicativo para quando essas coisas ruins acontecerem não prejudiquem os usuários e também a nós mesmos.

A fragilidade, no caso, é que entre o término do processamento da mensagem e a exclusão da mesma, pode ocorrer uma falha que impeça a sua exclusão, seja por uma falha de hardware ou mesmo por falta de conectividade com a fila de mensagens, porém o processamento foi executado até o fim, ou seja, o pedido foi emitido mas faltou excluir a mensagem. Após alguns instantes a mensagem que não foi excluída da fila voltará a estar visível e então será novamente consumida e processada, gerando assim uma duplicidade de processamento e a solicitação de dois pedidos idênticos para o mesmo cliente.

Uma outra forma, mas também frágil e talvez ainda pior, seria excluir a mensagem antes de processar o pedido. Caso haja uma falha durante o processamento, o pedido nunca seria emitido pois a mensagem já foi excluída da fila.

Toda essa fragilidade se dá pois não estamos em um contexto transacional onde tudo (pedido + mensagem) seria “confirmado” no final. Então aí entra o conceito de idempotência, onde nos dá subsídio para tratar com este tipo de cenário.

Como resolver

Como fazer para garantir que as mensagens sejam idempotentes?

Opção A: Contador de processamento

Um recurso da fila de mensagens do Azure é o DequeueCount, que nos diz quantas vezes esta mensagem foi lida da fila (e retornou para fila). Caso o DequeueCount for maior que zero é porque ela já pode ter sido processada alguma vez. Neste cenário, eu poderia avaliar os dados do sistema antes de processar a mensagem para identificar se o pedido do qual a mensagem trata já foi emitido.

Ocorrendo este caso, devemos pelo menos fazer um registro do ocorrido (log) para fins de auditoria e então excluir a mensagem sem processá-la.

Opção B: Usar mensageria com controle automático de duplicidade

Uma alternativa é utilizar sistemas de mensageria já implementam o controle de duplicidade de mensagem, por exemplo, o Azure Queue Service Bus tem um recurso configurável que permite detectar e eliminar a duplicidade de mensagens sem que o aplicativo saiba disso.

Neste cenário, o desafio está em calibrar a configuração de detecção de duplicidade com precisão.

Conclusão

Hoje em dia está cada vez mais comum utilizarmos algum sistema de mensageria em nossas soluções, e em grande parte das vezes é utilizado sistemas de mensageria que seguem o padrão de entrega de mensagem “pelo menos uma vez”, ou seja, o sistema apenas garante que não será perdido mensagens, mas a responsabilidade de garantir que ela seja processada apenas uma vez fica a cargo de quem a consome.

No texto acima citei duas formas de fazer este controle, não significa que sejam as únicas formas nem que são as formas corretas em qualquer cenário. Como em qualquer solução de TI não há uma solução “bala de prata” que sirva para qualquer cenário, mas é importante conhecermos as mais diversas soluções existentes para que possamos escolher dentre elas qual melhor se encaixa na nossa solução.

Além das opções citadas acima, conhece outra forma? Não deixe de contribuir escrevendo nos comentários abaixo.

Até a próxima.

Rafael Leonhardt

Referências