Um convite familiar é gravado no banco e a API tenta enviar o e-mail em seguida. Se o processo cair entre essas etapas, o convite fica pendente sem que o destinatário receba a mensagem. Inverter a ordem pode enviar um convite que nunca chegou a existir no banco.
Grave a intenção junto com o estado
No padrão outbox, a transação que cria o convite também insere um evento com ID próprio em uma tabela de saída. Um worker busca eventos pendentes e entrega cada um ao destino. Se o commit do convite falhar, o evento também desaparece. Se a API cair após o commit, o worker ainda encontra a tarefa.
Com vários workers, uma consulta com FOR UPDATE SKIP LOCKED pode coordenar a reserva de lotes. Se o envio ocorre fora da transação de reserva, registre uma concessão temporária com prazo de expiração. Assim, um segundo worker pode recuperar o evento se o primeiro cair depois de reservá-lo. Use tentativas com atraso e registre o motivo da última falha sem incluir dados sensíveis.
A falha mais importante acontece depois do envio
Se o provedor recebe a mensagem e o worker cai antes de gravar a confirmação, o evento pode ser entregue de novo. Use o ID do evento como chave de idempotência se o destino oferecer esse recurso. Quando o destino não deduplica, a operação precisa tolerar a possibilidade de duplicata.
O teste deve simular a queda depois de enviar e antes de confirmar. Verifique se o evento volta a ficar elegível e se a segunda tentativa conserva a mesma identidade.
PostgreSQL SELECT e SKIP LOCKED · Idempotência em APIs financeiras