Conteúdo original nessa thread do Twitter
Ei dev,
Você já deve ter ouvido falar de Kafka, RabbitMQ, SQS, consumidores, processamento assíncrono, etc., né?
Você sabe o que é, ou já ouviu falar sobre filas DEAD-LETTER e RETRY? Se quiser entender o conceito básico dessas duas coisas, cola mais.
cc @sseraphini
↓
Vamos pensar num cenário hipotético de abertura de conta num banco feito em duas etapas:
1-) O envio dos dados da proposta pra abertura da conta.
2-) Processo assíncrono de avaliação e efetuação da abertura em si de conta.
É um cenário simplificado.
Quando a gente fala de filas (ou tópicos no caso do Kafka) de retry e dead-letter, a gente associa ao consumo da mensagem. Quem publica as mensagens pro processamento nem precisa saber desse tipo de coisa, ok?
Sendo assim, vamos pensar no caso de falha do lado do consumidor.
Aqui, no cenário de falha, na hora da consulta a um serviço externo, aconteceu alguma coisa com o servidor – rolou um timeout.
Pára e pensa no que você faria nesse caso. Não dá pra deixar de aprovar uma proposta por causa de um timeout de um serviço – mancada com o proponente.
O natural aqui seria tentar de novo.
Vamos fazer isso de forma que o processamento fique quase uniforme – sem adicionar componentes pesados na arquitetura.
O primeiro passo é enviar essa mensagem que não foi possível processar para uma fila de retry.
Você deve estar se perguntando se não valeria a pena tentar algumas vezes antes de mandar para a fila de retry. Sim, você pode fazer isso, mas isso pode se tornar um problema se o timeout persistir por muito tempo.
Sigamos enviando a mensagem para retry no primeiro timeout, ok?
Agora precisamos dar o segundo passo que é fazer com que essa mensagem volte para o componente que processa as propostas.
Dependendo da tecnologia os padrões mudam um pouco. Mas a ideia central é a mesma: dar uma nova chance para que a mensagem seja processada. É um ciclo.
No RabbitMQ, usa-se uma combinação de expiração de mensagens com dead-letter exchanges. Já no Kafka, pode-se usar um conjunto de N tópicos de retry. Etc.
Novamente, a ideia continua a mesma: gerar um loop para uma nova tentativa de processamento da mensagem.
Falando em loop, é importante mencionar que não se deve consumir a mensagem da fila de retry imediatamente após ela ter ido parar lá. Caso contrário, isso poderia gerar uma fila enorme de mensagens se o erro persistir por muito tempo e mensagens novas chegarem constantemente.
Pra contornar esse problema do intervalo de reprocessamento é preciso adicionar algum tempo entre as tentativas. A gente poderia usar mecanismos de expiração ou até um conceito chamado de backoff exponencial. Mas não esquenta a cabeça com backoff agora.
Pqp, vc tá aqui ainda. Essa thread tá pior que Lost, né? Séries que nunca acabam. Mas aguenta mais um pouco – já tá aqui mesmo tem tanto tempo, mais um pouco não vai te matar.
Toma umas fotos de gente bonita e gostosa pra arejar um pouco, mas depois continua aí, blz? Não acabou.
Falando em coisas que não acabam, vc precisa dar um basta caso após N tentativas o erro ainda persistir.
Se o erro persistir OU para erros irrecuperáveis. Timeout é um erro recuperável. Mas no caso de uma mensagem inválida, não tem o que fazer – por exemplo, um CPF inválido.
Bom isso nos trás a um conceito importante nesse mundo de reprocessamento, retry, dead-letter:
- Erros transientes ou temporários.
- Erros irrecuperáveis ou permanentes.
Lembre-se disso, ok?
Agora vamos finalmente falar de dead-letter. Dead-letter é aquela fila pra qual mandamos as mensagens quando você decidiu que não tem mais o que fazer. Seja pelo excesso de tentativas de reprocessamento, seja por causa de um erro irrecuperável.
Simples assim.
Para as dead-letters você poderia ter outro consumidor pra fazer alguma coisa, um alarme que dispara quando um número X de mensagens for atingido ou até investigar manualmente as mensagens.
Dead-letter serve pra não descartar as mensagens no limbo.
Juro que tá acabando, só vou passar uns links de referência e já nos despedimos, tá?
Padrões de reprocessamento com o Kafka
https://eng.uber.com/reliable-reprocessing/
RabbitMQ e dead-letter exchanges (retry se faz com dead-letter exchanges no RabbitMQ)
Backoff exponencial (é usado pra mais coisas além de filas retry, ok).
https://en.wikipedia.org/wiki/Exponential_backoff
Nossa, obrigado demais pela moral de ter lido até aqui. É pra vc que dedico um tempão escrevendo essas coisas! ❤️
Um beijo e um abraço.
Top comments (6)
Francisco, acho que podemos usar também Circuit Breaker para o cenário de Timeout. O que você acha disso? Por que seguir com uma fila de Retry em vez de um Circuit Breaker com alguma política de redelivery no consumidor?
Conteúdo muito bacana de ler. Te acompanho no Twitter também. Parabéns!
Valeu, mano! Eu criei uma thread só sobre circuit breaker. Limito a quantidade de conceitos por thread senão acaba ficando muita coisa num lugar só, sabe?
dev.to/zanfranceschi/desafio-circu...
abs.
Francisco, aonde eu consigo mais desafios tipo os que vc faz ? de sistema "completo", estou adorando fazer
Boa pergunta, hein? rsrs
Que bom que está gostando!
Que post retardado.
Tu é bom.
Baita explicação!