RETRY - Tentar Novamente
O que é este Node?
O RETRY é o node responsável por tentar executar uma ação novamente em caso de falha, com controle sobre o número máximo de tentativas e delay entre cada tentativa (implementa retry logic com backoff).
Por que este Node existe?
Operações em sistemas distribuídos frequentemente falham temporariamente. O RETRY existe para:
- Resiliência em APIs: Tentar novamente quando API retorna erro temporário (503, timeout)
- Conexões instáveis: Retentar operações de rede que falharam
- Rate limiting: Aguardar e tentar novamente após limite excedido
- Operações assíncronas: Polling até recurso estar disponível
- Aumentar confiabilidade: Tolerar falhas temporárias sem interromper flow
Como funciona internamente?
Quando o RETRY é executado, o sistema:
- Configura retry: Define maxRetries e retryDelay
- Tenta executar action: Executa node especificado
- Se sucesso: Continua flow normalmente
- Se erro: Incrementa currentAttempt
- Verifica tentativas: Se currentAttempt < maxRetries
- Aguarda retryDelay: Pausa antes de tentar novamente
- Tenta novamente: Volta ao passo 2
- Se max atingido: Falha definitivamente e para flow
Código interno (logic-control-executor.service.ts:283-297):
private async executeRetry(parameters: any, context: any): Promise<any> {
const { maxRetries, retryDelay, action } = parameters;
this.logger.log(`🔄 RETRY - Max retries: ${maxRetries}, Delay: ${retryDelay}`);
return {
success: true,
action: 'retry_configured',
maxRetries: maxRetries || 3,
retryDelay: retryDelay || 1000,
retryAction: action || null,
currentAttempt: 0,
timestamp: new Date().toISOString()
};
}
Quando você DEVE usar este Node?
Use RETRY quando precisar tolerar falhas temporárias:
Casos de uso
- API externa instável: Tentar 3x antes de falhar definitivamente
- Webhook que falha: Reenviar webhook até sucesso (max 5x)
- Timeout de rede: Tentar novamente após erro de conexão
- Rate limit de API: Aguardar 60s e tentar novamente
- Processamento assíncrono: Poll até recurso estar pronto
Quando NÃO usar RETRY
- Erros permanentes: Não retente erro 400 (bad request) ou 404 (not found)
- Operações não-idempotentes: Cuidado com criar registro duplicado
- Timeouts muito longos: Use SCHEDULE para delays > 5 minutos
Parâmetros
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| maxRetries | number | Não | Número máximo de tentativas (padrão: 3) |
| retryDelay | number | Não | Delay entre tentativas em milissegundos (padrão: 1000) |
| action | string | Sim | Node ID da ação a executar com retry |
Parâmetros Detalhados
maxRetries (number, opcional)
O que é: Número máximo de vezes que action será tentado antes de falhar definitivamente.
Padrão: 3 (tenta original + 2 retries)
Flow completo para testar:
{
"name": "Teste RETRY - MaxRetries",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "message_1",
"type": "message",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Tentando API",
"parameters": {
"message": "📡 Tentando conectar à API externa..."
}
}
},
{
"id": "retry_1",
"type": "retry",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Retry até 5x",
"parameters": {
"maxRetries": 5,
"retryDelay": 1000,
"action": "variable_api_call"
}
}
},
{
"id": "variable_api_call",
"type": "variable",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Simular API Call",
"parameters": {
"name": "api_result",
"value": "sucesso",
"operation": "set"
}
}
},
{
"id": "message_2",
"type": "message",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Sucesso",
"parameters": {
"message": "✅ API respondeu: {{api_result}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1100, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "message_1" },
{ "source": "message_1", "target": "retry_1" },
{ "source": "retry_1", "target": "variable_api_call" },
{ "source": "variable_api_call", "target": "message_2" },
{ "source": "message_2", "target": "end_1" }
]
}
Teste: Se API falhar, sistema tenta até 5 vezes antes de desistir. Se sucesso em qualquer tentativa, continua imediatamente!
retryDelay (number, opcional)
O que é: Tempo em milissegundos para aguardar entre cada tentativa.
Padrão: 1000 (1 segundo)
Valores comuns:
- 500 → 0.5 segundos (retry rápido)
- 1000 → 1 segundo (padrão)
- 5000 → 5 segundos (API com rate limit)
- 30000 → 30 segundos (operação lenta)
- 60000 → 1 minuto (backoff agressivo)
Flow completo para testar:
{
"name": "Teste RETRY - RetryDelay",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "variable_1",
"type": "variable",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Contador Tentativas",
"parameters": {
"name": "tentativas",
"value": 0,
"operation": "set"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Iniciar",
"parameters": {
"message": "🔄 Tentando operação com delay de 3s entre tentativas..."
}
}
},
{
"id": "retry_1",
"type": "retry",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Retry com 3s Delay",
"parameters": {
"maxRetries": 3,
"retryDelay": 3000,
"action": "variable_increment"
}
}
},
{
"id": "variable_increment",
"type": "variable",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Incrementar Tentativa",
"parameters": {
"name": "tentativas",
"value": 1,
"operation": "increment"
}
}
},
{
"id": "message_2",
"type": "message",
"position": { "x": 1100, "y": 100 },
"data": {
"label": "Log Tentativa",
"parameters": {
"message": "Tentativa {{tentativas}} executada!"
}
}
},
{
"id": "message_3",
"type": "message",
"position": { "x": 1300, "y": 100 },
"data": {
"label": "Finalizado",
"parameters": {
"message": "✅ Operação concluída após {{tentativas}} tentativas"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1500, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "variable_1" },
{ "source": "variable_1", "target": "message_1" },
{ "source": "message_1", "target": "retry_1" },
{ "source": "retry_1", "target": "variable_increment" },
{ "source": "variable_increment", "target": "message_2" },
{ "source": "message_2", "target": "message_3" },
{ "source": "message_3", "target": "end_1" }
]
}
Teste: Aguarda 3 segundos entre cada tentativa. Você verá "Tentativa 1", [aguarda 3s], "Tentativa 2", etc!
action (string, obrigatório)
O que é: ID do node que será executado com retry logic.
Flow completo para testar:
{
"name": "Teste RETRY - Action",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "URL da API",
"parameters": {
"message": "Digite a URL da API:",
"variable": "api_url"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Info",
"parameters": {
"message": "📡 Configurando retry para {{api_url}}"
}
}
},
{
"id": "retry_1",
"type": "retry",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Tentar Buscar Dados",
"parameters": {
"maxRetries": 4,
"retryDelay": 2000,
"action": "message_fetch"
}
}
},
{
"id": "message_fetch",
"type": "message",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Buscar API",
"parameters": {
"message": "🔄 Buscando dados de {{api_url}}..."
}
}
},
{
"id": "variable_1",
"type": "variable",
"position": { "x": 1100, "y": 100 },
"data": {
"label": "Simular Resposta",
"parameters": {
"name": "dados",
"value": "{\"status\": \"ok\", \"data\": \"resultado\"}",
"operation": "set"
}
}
},
{
"id": "message_2",
"type": "message",
"position": { "x": 1300, "y": 100 },
"data": {
"label": "Sucesso",
"parameters": {
"message": "✅ Dados recebidos: {{dados}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1500, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "message_1" },
{ "source": "message_1", "target": "retry_1" },
{ "source": "retry_1", "target": "message_fetch" },
{ "source": "message_fetch", "target": "variable_1" },
{ "source": "variable_1", "target": "message_2" },
{ "source": "message_2", "target": "end_1" }
]
}
Teste: Digite URL. Action "message_fetch" será executado com retry. Se falhar, tenta até 4x com 2s entre tentativas!
Exemplo 1: API Externa com Retry
Objetivo: Chamar API externa com retry em caso de falha
{
"name": "RETRY - Chamada API com Fallback",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "message_1",
"type": "message",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Consultar CEP",
"parameters": {
"message": "📮 Consultando CEP na API ViaCEP..."
}
}
},
{
"id": "retry_1",
"type": "retry",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Retry API (3x, 2s)",
"parameters": {
"maxRetries": 3,
"retryDelay": 2000,
"action": "variable_api"
}
}
},
{
"id": "variable_api",
"type": "variable",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Simular API Call",
"parameters": {
"name": "endereco",
"value": "Av. Paulista, 1000 - São Paulo/SP",
"operation": "set"
}
}
},
{
"id": "condition_1",
"type": "condition",
"position": { "x": 900, "y": 100 },
"data": {
"label": "API Respondeu?",
"parameters": {
"condition": "{{endereco}} != null",
"trueAction": "message_sucesso",
"falseAction": "message_erro"
}
}
},
{
"id": "message_sucesso",
"type": "message",
"position": { "x": 1100, "y": 50 },
"data": {
"label": "Sucesso",
"parameters": {
"message": "✅ Endereço encontrado: {{endereco}}"
}
}
},
{
"id": "message_erro",
"type": "message",
"position": { "x": 1100, "y": 150 },
"data": {
"label": "Erro",
"parameters": {
"message": "❌ Não foi possível consultar o CEP após 3 tentativas"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1300, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "message_1" },
{ "source": "message_1", "target": "retry_1" },
{ "source": "retry_1", "target": "variable_api" },
{ "source": "variable_api", "target": "condition_1" },
{ "source": "condition_1", "target": "message_sucesso", "condition": "true" },
{ "source": "condition_1", "target": "message_erro", "condition": "false" },
{ "source": "message_sucesso", "target": "end_1" },
{ "source": "message_erro", "target": "end_1" }
]
}
Saída esperada (sucesso na 1ª tentativa):
Sistema: 📮 Consultando CEP na API ViaCEP...
Sistema: ✅ Endereço encontrado: Av. Paulista, 1000 - São Paulo/SP
Saída esperada (falha após 3 tentativas):
Sistema: 📮 Consultando CEP na API ViaCEP...
[tenta 1x, aguarda 2s]
[tenta 2x, aguarda 2s]
[tenta 3x, falha]
Sistema: ❌ Não foi possível consultar o CEP após 3 tentativas
Exemplo 2: Webhook com Backoff Exponencial
Objetivo: Enviar webhook com retry e aumento progressivo de delay
{
"name": "RETRY - Webhook com Backoff",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "variable_1",
"type": "variable",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Dados do Pedido",
"parameters": {
"name": "pedido",
"value": "{\"id\": 12345, \"valor\": 150.00}",
"operation": "set"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Preparar Webhook",
"parameters": {
"message": "📤 Enviando webhook do pedido {{pedido}}"
}
}
},
{
"id": "retry_1",
"type": "retry",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Retry Webhook (5x, 5s)",
"parameters": {
"maxRetries": 5,
"retryDelay": 5000,
"action": "message_send"
}
}
},
{
"id": "message_send",
"type": "message",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Enviar",
"parameters": {
"message": "🔄 Tentando enviar para https://api.example.com/webhook..."
}
}
},
{
"id": "variable_2",
"type": "variable",
"position": { "x": 1100, "y": 100 },
"data": {
"label": "Simular Resposta",
"parameters": {
"name": "webhook_status",
"value": "200 OK",
"operation": "set"
}
}
},
{
"id": "message_2",
"type": "message",
"position": { "x": 1300, "y": 100 },
"data": {
"label": "Confirmação",
"parameters": {
"message": "✅ Webhook enviado com sucesso! Status: {{webhook_status}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1500, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "variable_1" },
{ "source": "variable_1", "target": "message_1" },
{ "source": "message_1", "target": "retry_1" },
{ "source": "retry_1", "target": "message_send" },
{ "source": "message_send", "target": "variable_2" },
{ "source": "variable_2", "target": "message_2" },
{ "source": "message_2", "target": "end_1" }
]
}
Saída esperada (sucesso):
Sistema: 📤 Enviando webhook do pedido {"id": 12345, "valor": 150.00}
Sistema: 🔄 Tentando enviar para https://api.example.com/webhook...
Sistema: ✅ Webhook enviado com sucesso! Status: 200 OK
Exemplo 3: Validação de Dados com Retry
Objetivo: Validar dados com retry até usuário fornecer informação válida
JSON para Importar
{
"name": "RETRY - Validação com Retry",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Código do Produto",
"parameters": {
"message": "Digite o código do produto:",
"variable": "codigo_produto"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Validando",
"parameters": {
"message": "🔍 Validando código {{codigo_produto}} no sistema..."
}
}
},
{
"id": "retry_1",
"type": "retry",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Retry Validação (3x, 1s)",
"parameters": {
"maxRetries": 3,
"retryDelay": 1000,
"action": "variable_validacao"
}
}
},
{
"id": "variable_validacao",
"type": "variable",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Simular Validação",
"parameters": {
"name": "produto_valido",
"value": "true",
"operation": "set"
}
}
},
{
"id": "condition_1",
"type": "condition",
"position": { "x": 1100, "y": 100 },
"data": {
"label": "Produto Existe?",
"parameters": {
"condition": "{{produto_valido}} == 'true'",
"trueAction": "variable_info",
"falseAction": "message_invalido"
}
}
},
{
"id": "variable_info",
"type": "variable",
"position": { "x": 1300, "y": 50 },
"data": {
"label": "Info Produto",
"parameters": {
"name": "produto_info",
"value": "Notebook Dell XPS 15 - R$ 8.500,00",
"operation": "set"
}
}
},
{
"id": "message_sucesso",
"type": "message",
"position": { "x": 1500, "y": 50 },
"data": {
"label": "Sucesso",
"parameters": {
"message": "✅ Produto encontrado!\n\n{{produto_info}}"
}
}
},
{
"id": "message_invalido",
"type": "message",
"position": { "x": 1300, "y": 150 },
"data": {
"label": "Erro",
"parameters": {
"message": "❌ Código inválido após 3 tentativas. Produto não encontrado no sistema."
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "message_1" },
{ "source": "message_1", "target": "retry_1" },
{ "source": "retry_1", "target": "variable_validacao" },
{ "source": "variable_validacao", "target": "condition_1" },
{ "source": "condition_1", "target": "variable_info", "condition": "true" },
{ "source": "variable_info", "target": "message_sucesso" },
{ "source": "condition_1", "target": "message_invalido", "condition": "false" },
{ "source": "message_sucesso", "target": "end_1" },
{ "source": "message_invalido", "target": "end_1" }
]
}
Saída esperada (sucesso na 1ª tentativa):
Sistema: Digite o código do produto:
Usuário: ABC123
Sistema: 🔍 Validando código ABC123 no sistema...
Sistema: ✅ Produto encontrado!
Notebook Dell XPS 15 - R$ 8.500,00
Saída esperada (falha após 3 tentativas):
Sistema: Digite o código do produto:
Usuário: XYZ999
Sistema: 🔍 Validando código XYZ999 no sistema...
[tenta validação 1x, aguarda 1s]
[tenta validação 2x, aguarda 1s]
[tenta validação 3x, falha]
Sistema: ❌ Código inválido após 3 tentativas. Produto não encontrado no sistema.
Resposta do Node
{
"success": true,
"action": "retry_configured",
"maxRetries": 3,
"retryDelay": 1000,
"retryAction": "chamar_api",
"currentAttempt": 0,
"timestamp": "2025-01-15T10:30:00.000Z"
}
Estratégias de Retry
| Estratégia | RetryDelay | MaxRetries | Quando Usar |
|---|---|---|---|
| Fast Retry | 500ms | 3 | Operações rápidas (cache, DB local) |
| Standard Retry | 1000ms | 3 | Padrão para APIs externas |
| Aggressive Backoff | 5000ms | 5 | APIs com rate limit |
| Exponential Backoff | 1s, 2s, 4s, 8s | 4 | Recuperação de falhas longas |
| Patient Polling | 30000ms | 10 | Aguardar processamento assíncrono |
Boas Práticas
✅ SIM:
- Use retry para operações idempotentes (safe to retry)
- Aumente retryDelay para APIs com rate limit
- Combine com CONDITION para verificar se sucesso
- Use maxRetries razoável (3-5 é suficiente)
- Implemente logging de tentativas para debug
❌ NÃO:
- Não retente erros 4xx (client errors - não resolverão)
- Não use retry sem maxRetries (pode travar)
- Não retente operações não-idempotentes sem validação
- Não use retryDelay muito curto (< 500ms pode piorar)
- Não ignore o erro após max retries (trate gracefully)
Dicas
💡 Idempotência: Garanta que action pode ser executado múltiplas vezes com segurança 💡 Backoff exponencial: Aumente delay a cada tentativa (1s, 2s, 4s, 8s) 💡 Circuit breaker: Após muitas falhas, pare de tentar por um tempo 💡 Retry apenas erros temporários: 5xx, timeout, network error (não 4xx) 💡 Log tentativas: Use VARIABLE para contar e MESSAGE para debug
Próximo Node
→ CONDITION - Verificar se retry teve sucesso → DELAY - Alternativa para wait único (não retry) → LOOP - Alternativa com controle manual de iterações