O FireBanking implementa retry automático para garantir que webhooks importantes não sejam perdidos devido a falhas temporárias. Entenda como otimizar seu endpoint para máxima confiabilidade.
Política de Retry
Configuração Automática
Tentativas : Até 5 tentativas com backoff exponencial
Intervalos : 1s, 3s, 9s, 27s, 81s
Timeout : 30 segundos por tentativa
Total : Até ~2 minutos de tentativas
Retry automático ocorre quando:
Status HTTP 5xx (500, 502, 503, 504)
Timeout de conexão (>30s)
Erro de rede/DNS
Conexão recusada
Não há retry para:
Status 2xx (webhook processado)
Status 4xx (erro do cliente)
Status 200 com erro no body
Implementação Robusta
Resposta Adequada
Seu endpoint deve responder corretamente para evitar retries desnecessários:
app . post ( '/webhook' , async ( req , res ) => {
try {
// Responder IMEDIATAMENTE
res . status ( 200 ). send ( 'OK' );
// Processar ASSINCRONAMENTE
setImmediate (() => {
processWebhookAsync ( req . body );
});
} catch ( error ) {
// Log do erro mas ainda responder 200
console . error ( 'Webhook error:' , error );
res . status ( 200 ). send ( 'Received with errors' );
// Processar o erro separadamente
handleWebhookError ( req . body , error );
}
});
Importante : Sempre responda com status 200-299 se o webhook foi recebido corretamente, mesmo que haja erros no processamento interno.
Tratamento de Duplicatas
Idempotência
Implemente controle de idempotência para evitar processamento duplicado:
const Redis = require ( 'redis' );
const redis = Redis . createClient ();
app . post ( '/webhook' , async ( req , res ) => {
const webhookId = req . body . transaction_id ;
const attempt = req . body . webhook ?. attempt || 1 ;
// Verificar se já foi processado
const processed = await redis . get ( `webhook: ${ webhookId } ` );
if ( processed ) {
console . log ( `Webhook ${ webhookId } já processado - tentativa ${ attempt } ` );
return res . status ( 200 ). send ( 'Already processed' );
}
// Marcar como processado ANTES de processar
await redis . setex ( `webhook: ${ webhookId } ` , 3600 , 'processed' );
// Responder imediatamente
res . status ( 200 ). send ( 'OK' );
// Processar
try {
await processWebhook ( req . body );
console . log ( `Webhook ${ webhookId } processado com sucesso` );
} catch ( error ) {
// Log do erro mas manter como "processado"
console . error ( `Erro processando webhook ${ webhookId } :` , error );
}
});
Monitoramento de Retry
Métricas Importantes
Configure alertas para:
Taxa de retry > 10%
Tempo médio de resposta > 5 segundos
Taxa de falha final > 1%
Webhooks não processados há > 1 hora
Dashboard de Monitoramento
O painel FireBanking mostra:
Status de Entrega
Webhooks entregues no primeiro attempt
Webhooks que precisaram de retry
Webhooks que falharam definitivamente
Performance
Tempo de resposta do seu endpoint
Distribuição de tentativas
Padrões de falha por horário
Recuperação de Webhooks Perdidos
Sincronização Periódica
Implemente job de sincronização para webhooks que falharam definitivamente:
const cron = require ( 'node-cron' );
// Executar a cada hora
cron . schedule ( '0 * * * *' , async () => {
console . log ( 'Iniciando sincronização de webhooks perdidos' );
const lastHour = new Date ( Date . now () - 60 * 60 * 1000 );
const missingWebhooks = await findMissingWebhooks ( lastHour );
for ( const transaction of missingWebhooks ) {
try {
// Buscar status atual da transação
const currentStatus = await getTransactionStatus ( transaction . id );
// Simular webhook perdido
await processWebhook ({
event: ` ${ transaction . type } . ${ currentStatus . status } ` ,
transaction_id: transaction . id ,
data: currentStatus ,
timestamp: new Date (). toISOString (),
_recovered: true
});
console . log ( `Webhook recuperado: ${ transaction . id } ` );
} catch ( error ) {
console . error ( `Erro recuperando webhook ${ transaction . id } :` , error );
}
}
});
Boas Práticas
Endpoint Robusto
const app = express ();
// Timeout adequado
app . use ( timeout ( '25s' ));
// Rate limiting
app . use ( rateLimit ({
windowMs: 1000 , // 1 segundo
max: 100 // 100 requests por segundo
}));
// Body parser com limite
app . use ( express . json ({ limit: '1mb' }));
app . post ( '/webhook' , async ( req , res ) => {
try {
// Sempre responder primeiro
res . status ( 200 ). send ( 'OK' );
// Validação básica
if ( ! isValidWebhook ( req . body )) {
throw new Error ( 'Invalid webhook format' );
}
// Processamento
await processWebhook ( req . body );
} catch ( error ) {
// Log mas não falhar o webhook
logWebhookError ( error , req . body );
}
});
Próximos Passos