Mauricio Belusso

Arquitetura, sistemas distribuídos e o que está em produção.

View My GitHub Profile

Notas

03.10.2026

O lote não passa pela API

Restrição de Crédito · SQS

Anotações de crédito chegam a 300 mil CPFs e CNPJs numa execução. Esse volume não cabe num pedido HTTP. O pedido passa do tempo do gateway, o cliente tenta de novo e reenvia o que já tinha andado. O pico aparece como tráfego da API.

Por isso a API só aceita o trabalho e responde. O lote pode demorar, repetir ou falhar. A thread do pedido não espera.

Na mensageria, o par que mais usei foi outbox na saída e inbox na entrada.

O outbox evita dois passos que podem se separar: gravar o trabalho e publicar a mensagem. Os dois entram na mesma transação. Se ela confirma, a linha do outbox está lá. Se ela falha, nenhum dos dois fica.

@Transactional
void aceitar(String id) {
    salvarTrabalho(id);
    outbox.inserir(id);
}

Outro processo lê o que ainda não foi enviado, publica no SQS e marca a linha. Se ele morre depois de publicar e antes de marcar, publica de novo. Por isso a entrada precisa de inbox.

O inbox guarda o id da mensagem já tratada, na mesma transação da anotação. A fila pode entregar outra vez. O efeito não dobra. A mensagem só sai da fila depois que essa transação confirma.

@Transactional
boolean anotar(String id) {
    if (!inbox.registrar(id)) {
        return false;
    }
    gravarAnotacao(id);
    return true;
}

void consumir(String id, Mensagem mensagem) {
    anotar(id);
    mensagem.apagar();
}

registrar grava o id. Se ele já existe, a anotação não roda de novo. O id é único: se dois workers chegam juntos, um confirma e o outro falha nessa gravação. Se o processo morre depois da confirmação e antes de apagar, a fila entrega de novo e o inbox segura a repetição.

O tempo de visibilidade cobre o pior processamento daquele item. Se a mensagem volta enquanto o worker ainda trabalha, dois workers pegam o mesmo documento. O número desse tempo é o medido para o item, não um padrão copiado.

O que falha sempre sai da fila principal. Um item ruim não pode segurar o lote. Depois das tentativas, a mensagem vai para uma fila morta:

{
  "deadLetterTargetArn": "arn:aws:sqs:REGIAO:CONTA:anotacao-dlq",
  "maxReceiveCount": "TENTATIVAS"
}

No lugar de TENTATIVAS entra o número inteiro medido para aquele item: quantas falhas ele pode ter antes de sair da fila principal.

No ar, são 300 mil registros numa execução, e a API continua disponível.