Pular para o conteudo principal

Jobs Assíncronos, Filas e Workers: o Fluxo Completo

Como pensar do request inicial até o resultado final quando o trabalho sai da request web e vai para fila, retry e processamento em background.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

O problema

Tem trabalho que simplesmente não cabe bem dentro da request web.

Exemplos comuns:

  • gerar relatório
  • processar video
  • enviar lote de emails
  • importar arquivo grande

Quando o time tenta resolver tudo dentro do request, aparecem sintomas previsiveis:

  • timeout
  • usuário esperando demais
  • queda de throughput
  • falha parcial difícil de entender

A reação tipica e:

“Joga na fila.”

Só que esse conselho sozinho ainda e raso.

Porque fila não resolve o sistema inteiro. Ela resolve só uma parte.

Modelo mental

Pense em job assíncrono como um fluxo com cinco momentos:

  1. A aplicação aceita a intenção.
  2. O estado inicial do job fica persistido.
  3. O trabalho entra numa fila.
  4. Um worker processa com retry e idempotencia.
  5. O resultado ou falha fica visível para alguém.

Se qualquer uma dessas partes fica fraca, o sistema vira uma maquina de “não sei onde isso travou”.

Quebrando o problema

A request não entrega resultado. Ela entrega aceite

Em muito caso assíncrono, a resposta certa para o cliente não e “pronto”.

E algo mais honesto:

  • “aceitei seu pedido”
  • “seu job foi criado”
  • “acompanhe por este id”

Isso costuma virar um 202 Accepted ou um 200 com semântica explicita de processamento pendente.

O estado do job precisa existir fora da fila

Esse ponto e crucial.

Se você só publica uma mensagem e não registra estado, depois fica ruim responder perguntas basicas:

  • esse job existe?
  • esta pendente?
  • esta processando?
  • falhou?
  • terminou?

Por isso muita arquitetura cria um registro do job antes:

  • queued
  • processing
  • completed
  • failed

Fila sem estado de negócio costuma deixar rastreabilidade fraca.

Enfileirar com segurança importa

Aqui mora uma falha classica:

  • salva no banco, mas não publica na fila
  • publica na fila, mas não salva no banco

Os dois deixam o sistema incoerente.

Dependendo do caso, você precisa de estratégia para reduzir essa janela, como:

  • transação bem desenhada
  • outbox pattern
  • reconciliação operacional

O ponto não e decorar nome bonito.

E evitar que a intenção se perca no meio.

Worker não e script solto

O worker precisa fazer mais do que “ler mensagem e rodar função”.

Ele normalmente precisa:

  • buscar ou validar o job
  • marcar como processing
  • executar a tarefa
  • persistir resultado
  • confirmar consumo
  • reagir a falha

E como mensagem pode repetir, o worker precisa aguentar reprocessamento sem estrago.

Se ele chama serviço externo, grava arquivo ou muda estado de negócio, essa repetição precisa ser pensada antes.

Retry sem critério piora tudo

Nem toda falha merece retry igual.

Falha transitoria pode pedir:

  • retry
  • backoff
  • limite de tentativas

Falha permanente pode pedir:

  • marcar como failed
  • mandar para DLQ
  • abrir caminho de inspeção manual

Retry infinito em erro permanente só move o problema de lugar.

E polling sem contrato claro também.

Se o cliente vai consultar status, ele precisa saber o que cada estado significa e quando vale tentar de novo.

Exemplo simples

Imagine exportacao de CSV.

O usuário clica em “Exportar pedidos”.

Fluxo melhor:

  1. API cria um job exp_123 com status queued.
  2. API publica mensagem com job_id=exp_123.
  3. API responde ao cliente com o id do job.
  4. Worker consome a mensagem e muda status para processing.
  5. Worker gera o arquivo, salva a URL e marca como completed.
  6. O cliente consulta GET /exports/exp_123 ou recebe webhook quando terminar.

Se o worker cair depois de metade do processo, o sistema precisa saber onde esta o job.

Se a mensagem reaparecer, o worker precisa entender se:

  • ainda deve processar
  • já concluiu
  • falhou de forma definitiva

Sem esse desenho, a fila vira só uma desculpa elegante para esconder falta de controle.

Erros comuns

  • Tratar fila como substituto de modelagem de estado.
  • Enfileirar payload gigante em vez de referência para o trabalho.
  • Fazer retry sem distinguir erro transitorio de erro permanente.
  • Não ter idempotencia e depois sofrer com job duplicado.
  • Não expor status para cliente, time de suporte ou operação.

Como um senior pensa

Quem tem mais experiência olha para job assíncrono como fluxo operacional, não só como padrão de código.

O pensamento costuma ser:

“Como essa intenção entra, como ela progride, como ela falha, como ela reaparece e como alguém descobre o que aconteceu?”

Essa pergunta obriga o sistema a ficar explicavel.

E sistema explicavel quase sempre e mais resiliente.

O que o entrevistador quer ver

Em entrevista, falar “eu usaria fila” quase nunca basta.

O avaliador quer ver se você enxerga o caminho inteiro.

Sinais bons:

  • você fala de estado do job
  • menciona 202 Accepted ou resposta equivalente
  • descreve retry com critério
  • traz idempotencia para o worker
  • explica como o cliente acompanha o resultado

Uma resposta forte costuma soar assim:

“Eu aceitaria a intenção, registraria o job, publicaria na fila e deixaria o worker processar com retry e idempotencia. O cliente não esperaria o trabalho terminar dentro da request. Ele consultaria o status ou receberia notificação.”

Fila desacopla latência. Estado e observabilidade desacoplam desespero.

Resumo rápido

O que vale manter na cabeça

Checklist de pratica

Use isto ao responder

Você concluiu este artigo

Próximo artigo Locks, Filas e Retries: Quando Usar Cada um Artigo anterior Exactly-once Quase Nunca Existe, Como Pensar Direito Sobre Isso

Continue explorando

Artigos relacionados