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:
- Processar arrays: Iterar sobre lista de itens
- Tentativas múltiplas: Repetir até sucesso
- Automação em massa: Executar ação N vezes
- Polling: Verificar status repetidamente até mudança
- Limite de segurança: maxIterations previne loops infinitos
Como funciona internamente?
Quando o LOOP é executado, o sistema:
- Avalia condição inicial: Verifica se deve começar o loop
- Executa loopAction: Vai para node especificado
- Incrementa contador: currentIteration++
- Reavalia condição: Verifica se deve continuar
- Verifica maxIterations: Safety limit para evitar loop infinito
- Se condição false ou max atingido: Sai do loop
- 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:
- Processar lista: Enviar mensagem para cada item de array
- Tentativas limitadas: Tentar até 3x antes de desistir
- Polling: Verificar status a cada 5s até completar
- Automação em massa: Criar 10 registros
- 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