Pular para conteúdo

LOOP - Repetir Ações

O que é este Node?

O LOOP é o node responsável por repetir ações múltiplas vezes baseado em uma condição ou número máximo de iterações (equivalente ao while/for da programação).

Por que este Node existe?

Flows precisam processar listas e repetir operações. O LOOP existe para:

  1. Processar arrays: Iterar sobre lista de itens
  2. Tentativas múltiplas: Repetir até sucesso
  3. Automação em massa: Executar ação N vezes
  4. Polling: Verificar status repetidamente até mudança
  5. Limite de segurança: maxIterations previne loops infinitos

Como funciona internamente?

Quando o LOOP é executado, o sistema:

  1. Avalia condição inicial: Verifica se deve começar o loop
  2. Executa loopAction: Vai para node especificado
  3. Incrementa contador: currentIteration++
  4. Reavalia condição: Verifica se deve continuar
  5. Verifica maxIterations: Safety limit para evitar loop infinito
  6. Se condição false ou max atingido: Sai do loop
  7. Se condição true: Volta para loopAction (repete)

Código interno (logic-control-executor.service.ts:114-132):

private async executeLoop(parameters: any, context: any): Promise<any> {
  const { condition, maxIterations, loopAction, variables } = parameters;

  const maxIter = maxIterations || 10; // Safety limit
  const currentVariables = variables || context.variables || {};

  return {
    success: true,
    action: 'loop_setup',
    condition: condition,
    maxIterations: maxIter,
    loopAction: loopAction,
    currentIteration: 0,
    shouldContinue: this.evaluateCondition(condition, currentVariables),
    timestamp: new Date().toISOString()
  };
}

Quando você DEVE usar este Node?

Use LOOP quando precisar repetir operações:

Casos de uso:

  1. Processar lista: Enviar mensagem para cada item de array
  2. Tentativas limitadas: Tentar até 3x antes de desistir
  3. Polling: Verificar status a cada 5s até completar
  4. Automação em massa: Criar 10 registros
  5. Iteração condicional: Continuar enquanto status != "completo"

Quando NÃO usar LOOP:

  • Loop infinito: Sempre defina maxIterations
  • Operações síncronas longas: Use jobs assíncronos
  • Sem condição de saída: Loop ficará travado

Parâmetros

Campo Tipo Obrigatório Descrição
condition string Sim Expressão booleana para continuar
maxIterations number Não Máximo de iterações (padrão: 10, safety)
loopAction string Sim Node ID para executar em cada iteração
variables object Não Variáveis (context.variables padrão)

Parâmetros Detalhados

condition (string, obrigatório)

O que é: Expressão que define quando o loop deve continuar (while this is true).

Flow completo para testar:

{
  "name": "Teste LOOP - Condition",
  "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": "Inicializar Contador",
        "parameters": {
          "name": "contador",
          "value": 0,
          "operation": "set"
        }
      }
    },
    {
      "id": "loop_1",
      "type": "loop",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Loop até 3",
        "parameters": {
          "condition": "{{contador}} < 3",
          "maxIterations": 5,
          "loopAction": "message_1"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Mensagem Loop",
        "parameters": {
          "message": "Iteração {{contador}}"
        }
      }
    },
    {
      "id": "variable_2",
      "type": "variable",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Incrementar",
        "parameters": {
          "name": "contador",
          "value": 1,
          "operation": "increment"
        }
      }
    },
    {
      "id": "message_2",
      "type": "message",
      "position": { "x": 1100, "y": 100 },
      "data": {
        "label": "Loop Completo",
        "parameters": {
          "message": "✅ Loop finalizado! Contador final: {{contador}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1300, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "variable_1" },
    { "source": "variable_1", "target": "loop_1" },
    { "source": "loop_1", "target": "message_1", "condition": "true" },
    { "source": "message_1", "target": "variable_2" },
    { "source": "variable_2", "target": "loop_1" },
    { "source": "loop_1", "target": "message_2", "condition": "false" },
    { "source": "message_2", "target": "end_1" }
  ]
}

Teste: Loop executa 3 vezes (contador 0, 1, 2) e depois sai!

maxIterations (number, opcional)

O que é: Número máximo de iterações para evitar loop infinito.

Padrão: 10 (safety limit)

Flow completo para testar:

{
  "name": "Teste LOOP - MaxIterations",
  "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",
        "parameters": {
          "name": "i",
          "value": 0,
          "operation": "set"
        }
      }
    },
    {
      "id": "loop_1",
      "type": "loop",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Max 5 Iterações",
        "parameters": {
          "condition": "true",
          "maxIterations": 5,
          "loopAction": "message_1"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Iteração",
        "parameters": {
          "message": "Iteração {{i}}"
        }
      }
    },
    {
      "id": "variable_2",
      "type": "variable",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Incrementar",
        "parameters": {
          "name": "i",
          "value": 1,
          "operation": "increment"
        }
      }
    },
    {
      "id": "message_2",
      "type": "message",
      "position": { "x": 1100, "y": 100 },
      "data": {
        "label": "Fim",
        "parameters": {
          "message": "Máximo de iterações atingido! Total: {{i}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1300, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "variable_1" },
    { "source": "variable_1", "target": "loop_1" },
    { "source": "loop_1", "target": "message_1", "condition": "true" },
    { "source": "message_1", "target": "variable_2" },
    { "source": "variable_2", "target": "loop_1" },
    { "source": "loop_1", "target": "message_2", "condition": "false" },
    { "source": "message_2", "target": "end_1" }
  ]
}

Teste: Mesmo com condition="true" (sempre verdadeiro), para após 5 iterações!

Exemplo 1: Contador Simples

Objetivo: Demonstrar loop básico contando de 1 até 5

JSON para Importar

{
  "name": "Loop Contador 1 a 5",
  "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": "Intro",
        "parameters": {
          "message": "🔄 Iniciando contagem de 1 a 5..."
        }
      }
    },
    {
      "id": "variable_1",
      "type": "variable",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Inicializar",
        "parameters": {
          "name": "numero",
          "value": 1,
          "operation": "set"
        }
      }
    },
    {
      "id": "loop_1",
      "type": "loop",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Loop até 5",
        "parameters": {
          "condition": "{{numero}} <= 5",
          "maxIterations": 10,
          "loopAction": "message_2"
        }
      }
    },
    {
      "id": "message_2",
      "type": "message",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Mostrar Número",
        "parameters": {
          "message": "Número: {{numero}}"
        }
      }
    },
    {
      "id": "variable_2",
      "type": "variable",
      "position": { "x": 1100, "y": 100 },
      "data": {
        "label": "Incrementar",
        "parameters": {
          "name": "numero",
          "value": 1,
          "operation": "increment"
        }
      }
    },
    {
      "id": "message_3",
      "type": "message",
      "position": { "x": 1300, "y": 100 },
      "data": {
        "label": "Finalizar",
        "parameters": {
          "message": "✅ Contagem completa!"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1500, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "message_1" },
    { "source": "message_1", "target": "variable_1" },
    { "source": "variable_1", "target": "loop_1" },
    { "source": "loop_1", "target": "message_2", "condition": "true" },
    { "source": "message_2", "target": "variable_2" },
    { "source": "variable_2", "target": "loop_1" },
    { "source": "loop_1", "target": "message_3", "condition": "false" },
    { "source": "message_3", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: 🔄 Iniciando contagem de 1 a 5...
Sistema: Número: 1
Sistema: Número: 2
Sistema: Número: 3
Sistema: Número: 4
Sistema: Número: 5
Sistema: ✅ Contagem completa!

Exemplo 2: Processamento de Lista de Clientes

Objetivo: Demonstrar loop processando uma lista/array de itens

JSON para Importar

{
  "name": "Loop Processar Lista Clientes",
  "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": "Intro",
        "parameters": {
          "message": "📋 Processando lista de clientes..."
        }
      }
    },
    {
      "id": "variable_1",
      "type": "variable",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Inicializar Índice",
        "parameters": {
          "name": "indice",
          "value": 0,
          "operation": "set"
        }
      }
    },
    {
      "id": "variable_2",
      "type": "variable",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Total de Clientes",
        "parameters": {
          "name": "total",
          "value": 3,
          "operation": "set"
        }
      }
    },
    {
      "id": "loop_1",
      "type": "loop",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Loop por Clientes",
        "parameters": {
          "condition": "{{indice}} < {{total}}",
          "maxIterations": 10,
          "loopAction": "message_2"
        }
      }
    },
    {
      "id": "message_2",
      "type": "message",
      "position": { "x": 1100, "y": 100 },
      "data": {
        "label": "Processar Cliente",
        "parameters": {
          "message": "✅ Cliente {{indice}} processado"
        }
      }
    },
    {
      "id": "variable_3",
      "type": "variable",
      "position": { "x": 1300, "y": 100 },
      "data": {
        "label": "Próximo Cliente",
        "parameters": {
          "name": "indice",
          "value": 1,
          "operation": "increment"
        }
      }
    },
    {
      "id": "message_3",
      "type": "message",
      "position": { "x": 1500, "y": 100 },
      "data": {
        "label": "Finalizar",
        "parameters": {
          "message": "🎉 Todos os {{total}} clientes foram processados!"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "message_1" },
    { "source": "message_1", "target": "variable_1" },
    { "source": "variable_1", "target": "variable_2" },
    { "source": "variable_2", "target": "loop_1" },
    { "source": "loop_1", "target": "message_2", "condition": "true" },
    { "source": "message_2", "target": "variable_3" },
    { "source": "variable_3", "target": "loop_1" },
    { "source": "loop_1", "target": "message_3", "condition": "false" },
    { "source": "message_3", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: 📋 Processando lista de clientes...
Sistema: ✅ Cliente 0 processado
Sistema: ✅ Cliente 1 processado
Sistema: ✅ Cliente 2 processado
Sistema: 🎉 Todos os 3 clientes foram processados!

Resposta do Node

{
  "success": true,
  "action": "loop_setup",
  "condition": "{{contador}} < 3",
  "maxIterations": 10,
  "loopAction": "message_1",
  "currentIteration": 0,
  "shouldContinue": true,
  "timestamp": "2025-01-15T10:30:00.000Z"
}

Estrutura de Loop

START
  ↓
VARIABLE (inicializar contador)
  ↓
LOOP (verifica condição)
  ├─ true → LOOP_ACTION
  │          ↓
  │       VARIABLE (incrementar)
  │          ↓
  │       volta para LOOP
  │
  └─ false → CONTINUA FLOW

Boas Práticas

SIM: - Sempre inicialize variáveis antes do loop - Sempre defina maxIterations (safety) - Sempre incremente/modifique variável na condição - Use condições que eventualmente se tornam false

NÃO: - Não crie loops sem condição de saída - Não use maxIterations muito alto (> 100) - Não esqueça de incrementar contador - Não confie apenas em condição sem maxIterations

Dicas

💡 Safety first: maxIterations previne loops infinitos 💡 Incremente sempre: Garanta que condição eventualmente fica false 💡 Debug: Use MESSAGE dentro do loop para ver progresso 💡 Performance: Loops longos (> 50 iterações) podem ser lentos

Próximo Node

CONDITION - Condições simples → VARIABLE - Manipular contadores → RETRY - Retry com loop embutido