A senha do açougue × o alto-falante do mercado
No açougue, você tira uma senha e um único atendente — o que ficar livre — chama o seu número. É a fila: a tarefa vai para um atendente só, e contratar mais atendentes faz a fila andar mais rápido. Já o anúncio no alto-falante ('promoção no corredor 3') chega a todos os clientes de uma vez — é o pub/sub: um mesmo aviso, ouvido por todo mundo que estiver escutando. Trocar um pelo outro é ou mandar o alto-falante atender um cliente, ou tirar senha para uma promoção.
O que a mensagem representa
A escolha não é sobre a tecnologia, é sobre o significado da mensagem. Uma tarefa ('gere esta nota fiscal') deve ser feita uma vez: é fila, e vários workers competem por ela. Um fato ('o pedido foi pago') pode interessar a muitos: é pub/sub, e cada inscrito recebe a própria cópia.
O sintoma de ter escolhido errado é claro. Pub/sub onde devia ser fila: a mesma nota é gerada três vezes, uma por consumidor. Fila onde devia ser pub/sub: o faturamento é avisado do pagamento, mas o estoque e o e-mail nunca ficam sabendo.
Os dois modelos se combinam, e é aí que a mensageria fica poderosa. Um evento pedido-pago é publicado num tópico; entre os inscritos estão o serviço de faturamento, o de estoque e o de e-mail. Cada um recebe sua cópia (pub/sub) e, internamente, cada serviço pode ter uma fila de workers processando esses eventos em paralelo (fila). O fato é difundido uma vez; o trabalho que ele gera em cada consumidor é dividido entre muitos.
Vale ligar isso ao Observer: pub/sub é o Observer levado para além do processo. No Observer, o sujeito mantém a lista de ouvintes e os notifica por chamada de método, no mesmo processo e de forma síncrona. No pub/sub, o broker é o intermediário: o publicador não conhece os inscritos, a entrega é assíncrona e durável, e produtor e consumidor podem estar em máquinas, linguagens e tempos diferentes. É o mesmo desacoplamento 'quem avisa não conhece quem escuta', agora atravessando a rede.
Como isso aparece na prática
O e-mail enviado três vezes
Cenário
Um time ligou três serviços a um tópico pub/sub de 'novo usuário', achando que balanceava carga. Cada novo cadastro disparava o e-mail de boas-vindas três vezes, uma por serviço inscrito.
Como o padrão entra
O envio de e-mail virou uma fila de trabalho com vários workers competindo pela mesma mensagem, enquanto o tópico pub/sub ficou só para os fatos que realmente interessavam a várias partes.
Trade-off: Passou a existir uma fila a mais para operar. Em troca, cada e-mail voltou a ser enviado exatamente uma vez, com a vazão escalando pelo número de workers.
O estoque que nunca soube do pagamento
Cenário
O pagamento era colocado numa fila lida pelo faturamento. Quando o estoque também precisou reagir ao pagamento, ele foi ligado à mesma fila — e passou a roubar metade das mensagens do faturamento.
Como o padrão entra
O pagamento virou um evento publicado num tópico; faturamento e estoque viraram inscritos independentes, cada um com sua própria cópia de cada evento.
Trade-off: Cada inscrito precisou ser idempotente, já que agora todos recebem tudo. Em troca, adicionar um quarto interessado ao fato passou a ser só mais uma inscrição, sem tocar em quem já existia.
Onde isto dá errado
Pub/Sub para dividir trabalho
Ligar vários consumidores a um tópico não balanceia carga — replica. Cada inscrito recebe a mensagem inteira, então a tarefa é executada uma vez por consumidor. Para dividir trabalho, o modelo é fila com workers competindo.
Fila para difundir um fato
Colocar vários interessados na mesma fila faz eles competirem: cada mensagem vai para um só. Quem precisa que todos saibam do mesmo evento usa pub/sub, não uma fila compartilhada.
Esquecer que pub/sub exige idempotência
Como todo inscrito recebe cada evento, e a entrega costuma ser ao menos uma vez, cada consumidor precisa tolerar receber a mesma mensagem de novo sem duplicar o efeito.
Enviar para um × publicar para todos
// FILA (work queue): uma mensagem, UM consumidor a processa.
// Serve para DIVIDIR trabalho entre workers concorrentes.
await fila.enviar({ tipo: "gerar-nota", pedidoId: 42 });
// N workers competem; só um pega a mensagem. Somar workers = mais vazão.
// PUB/SUB (topico): um evento, TODOS os inscritos recebem uma cópia.
// Serve para NOTIFICAR várias partes independentes do mesmo fato.
await topico.publicar({ tipo: "pedido-pago", pedidoId: 42 });
// -> faturamento recebe, -> estoque recebe, -> e-mail recebe.
// Cada inscrito tem sua própria cópia e seu próprio ritmo.
// A pergunta que decide: o trabalho deve ser feito UMA vez
// (fila) ou o fato deve ser CONHECIDO por vários (pub/sub)?
// Errar isso ou duplica trabalho, ou perde quem precisava saber.Quando usar × quando evitar
Use quando
3- Fila para distribuir tarefas entre workers e escalar vazão.
- Pub/Sub para notificar várias partes do mesmo fato.
- Os dois juntos: difundir o evento, dividir o trabalho em cada consumidor.
Evite quando
2- Pub/Sub quando a tarefa deve ser feita exatamente uma vez.
- Fila quando várias partes precisam do mesmo fato.
Testar o que ficou
3 armadilhas de Fila × Pub/Sub viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.
Onde isto aparece de verdade
Você já usa isto, talvez sem saber o nome.
SQS × SNS na AWSSQS é fila (uma mensagem, um consumidor a processa); SNS é pub/sub (um evento, todos os inscritos recebem) — a distinção virada produto.RabbitMQ: queue × exchange fanoutA fila entrega a um worker do grupo; a exchange fanout replica para todas as filas inscritas — os dois modelos no mesmo broker.consumer groups do KafkaDentro de um grupo, cada mensagem vai a um consumidor (fila); grupos diferentes recebem tudo (pub/sub) — os dois ao mesmo tempo.
O padrão em uma linha
Sem nome de domínio, sem cerimônia. Só a ideia.
// Fila: um consumidor. Pub/Sub: todos os inscritos.
await fila.send(job); // trabalho
bus.publish("PedidoCriado", e); // fatoO que ele cobra
1 salto a mais entre a chamada e o efeito.
- Escolher errado acopla demais (pub/sub onde queria dividir trabalho) ou perde entregas (fila onde queria broadcast)
- Ambos exigem um broker a operar, monitorar e dimensionar, com sua própria falha e latência
Não vale se: produtor e consumidor vivem no mesmo processo e a chamada pode ser síncrona — aí um broker entre eles é infraestrutura sem propósito.
Onde isto aparece
Continue por aqui
- ObserverDefine uma dependência um-para-muitos: quando um objeto muda de estado, todos os seus dependentes são notificados automaticamente.
- WebhooksEm vez de perguntar 'já aconteceu?' de minuto em minuto, você registra uma URL e o outro sistema te chama quando acontece. É o Observer atravessando a internet — com tudo que a rede cobra por isso: assinatura, retry e duplicata.
- BackpressureQuando o produtor é mais rápido que o consumidor, alguém tem que ceder. Backpressure é o sinal de 'vá mais devagar' subindo a cadeia: o consumidor dita o ritmo, o produtor respeita, e o buffer entre eles não cresce até estourar a memória. Sem ele, a diferença de velocidade não some — ela vira um buffer infinito, latência crescente e, no fim, um out-of-memory.