Pular para conteúdo

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:

  1. Resiliência em APIs: Tentar novamente quando API retorna erro temporário (503, timeout)
  2. Conexões instáveis: Retentar operações de rede que falharam
  3. Rate limiting: Aguardar e tentar novamente após limite excedido
  4. Operações assíncronas: Polling até recurso estar disponível
  5. Aumentar confiabilidade: Tolerar falhas temporárias sem interromper flow

Como funciona internamente?

Quando o RETRY é executado, o sistema:

  1. Configura retry: Define maxRetries e retryDelay
  2. Tenta executar action: Executa node especificado
  3. Se sucesso: Continua flow normalmente
  4. Se erro: Incrementa currentAttempt
  5. Verifica tentativas: Se currentAttempt < maxRetries
  6. Aguarda retryDelay: Pausa antes de tentar novamente
  7. Tenta novamente: Volta ao passo 2
  8. 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

  1. API externa instável: Tentar 3x antes de falhar definitivamente
  2. Webhook que falha: Reenviar webhook até sucesso (max 5x)
  3. Timeout de rede: Tentar novamente após erro de conexão
  4. Rate limit de API: Aguardar 60s e tentar novamente
  5. 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