Repository: kestra-io/kestra
Issue: Infinite loop in the executor if a flowable task fail
Labels: bug

### Expected Behavior

Even if a flowable task fail, there should not be any infinite loop in the executor.

### Actual Behaviour

The executor entre an infinite loop as it will not be able to return the next task to run so the same task will be executed again and again.

### Steps To Reproduce

_No response_

### Environment Information

- Kestra Version: 0.10
- Operating System (OS / Docker / Kubernetes):
- Java Version (If not docker):


### Example flow

```yaml
id: infinite-looping
namespace: bug
tasks:
- id: channel
  type: io.kestra.core.tasks.flows.EachParallel
  tasks:
  - id: type
    type: io.kestra.core.tasks.flows.EachParallel
    tasks:
    - id: vision
      type: io.kestra.core.tasks.flows.EachParallel
      tasks:
      - id: metaseg_date
        type: io.kestra.core.tasks.flows.EachParallel
        tasks:
          - id: if
            type: io.kestra.core.tasks.flows.If
            condition: "{{parents[0].taskrun.value == 'CUMULATIVE' and {% for entry in json(taskrun.value) %}{{ entry.key }}{% endfor %}== 'NEW_MONTH'}}"
            then:
              - id: when-true
                type: io.kestra.core.tasks.log.Log
                message: 'Condition was true'
            else:
              - id: when-false
                type: io.kestra.core.tasks.log.Log
                message: 'Condition was false'
        value: "[{\"NEW_MONTH\":\"2018-01-01\"}, {\"NEW_YEAR\":\"2018-01-01\"}, {\"EXISTING\":\"2018-01-01\"}]"
      value: "[\"MONTHLY\", \"CUMULATIVE\"]"
    value: "[\"INHABITANT\", \"MEMBERS\"]"
  value: "[\"OFFLINE_ONLY\", \"ONLINE_ONLY\", \"OMNICANAL\"]"
```

Issue comments:

Pull request review comments:

Patch that resolved the issue:
diff --git a/core/src/main/java/io/kestra/core/runners/ExecutorService.java b/core/src/main/java/io/kestra/core/runners/ExecutorService.java
index 7a5ff25cff..63717e1143 100644
--- a/core/src/main/java/io/kestra/core/runners/ExecutorService.java
+++ b/core/src/main/java/io/kestra/core/runners/ExecutorService.java
@@ -221,23 +221,27 @@ private List<TaskRun> childNextsTaskRun(Executor executor, TaskRun parentTaskRun
 
         if (parent instanceof FlowableTask<?> flowableParent) {
 
-            List<NextTaskRun> nexts = flowableParent.resolveNexts(
-                runContextFactory.of(
-                    executor.getFlow(),
-                    parent,
+            try {
+                List<NextTaskRun> nexts = flowableParent.resolveNexts(
+                    runContextFactory.of(
+                        executor.getFlow(),
+                        parent,
+                        executor.getExecution(),
+                        parentTaskRun
+                    ),
                     executor.getExecution(),
                     parentTaskRun
-                ),
-                executor.getExecution(),
-                parentTaskRun
-            );
-
-            if (nexts.size() > 0) {
-                return this.saveFlowableOutput(
-                    nexts,
-                    executor,
-                    parentTaskRun
                 );
+
+                if (nexts.size() > 0) {
+                    return this.saveFlowableOutput(
+                        nexts,
+                        executor,
+                        parentTaskRun
+                    );
+                }
+            } catch (Exception e) {
+                log.warn("Unable to resolve the next tasks to run", e);
             }
         }
 


Test patch:
diff --git a/core/src/test/java/io/kestra/core/tasks/flows/BadFlowableTest.java b/core/src/test/java/io/kestra/core/tasks/flows/BadFlowableTest.java
index 03948608f0..1502fbae79 100644
--- a/core/src/test/java/io/kestra/core/tasks/flows/BadFlowableTest.java
+++ b/core/src/test/java/io/kestra/core/tasks/flows/BadFlowableTest.java
@@ -19,4 +19,12 @@ void sequential() throws TimeoutException {
         assertThat(execution.getTaskRunList(), hasSize(2));
         assertThat(execution.getState().getCurrent(), is(State.Type.FAILED));
     }
+
+    @Test // this test is a non-reg for an infinite loop in the executor
+    void flowableWithParentFail() throws TimeoutException {
+        Execution execution = runnerUtils.runOne("io.kestra.tests", "flowable-with-parent-fail");
+
+        assertThat(execution.getTaskRunList(), hasSize(5));
+        assertThat(execution.getState().getCurrent(), is(State.Type.FAILED));
+    }
 }
diff --git a/core/src/test/java/io/kestra/core/tasks/flows/TemplateTest.java b/core/src/test/java/io/kestra/core/tasks/flows/TemplateTest.java
index 664a935780..a847a1412d 100644
--- a/core/src/test/java/io/kestra/core/tasks/flows/TemplateTest.java
+++ b/core/src/test/java/io/kestra/core/tasks/flows/TemplateTest.java
@@ -85,7 +85,7 @@ public static void withFailedTemplate(RunnerUtils runnerUtils, TemplateRepositor
 
         assertThat(execution.getTaskRunList(), hasSize(1));
         assertThat(execution.getState().getCurrent(), is(State.Type.FAILED));
-        LogEntry matchingLog = TestsUtils.awaitLog(logs, logEntry -> logEntry.getMessage().equals("Can't find flow template 'io.kestra.tests.invalid'") && logEntry.getLevel() == Level.ERROR);
+        LogEntry matchingLog = TestsUtils.awaitLog(logs, logEntry -> logEntry.getMessage().endsWith("Can't find flow template 'io.kestra.tests.invalid'") && logEntry.getLevel() == Level.ERROR);
         assertThat(matchingLog, notNullValue());
     }
 
diff --git a/core/src/test/resources/flows/valids/flowable-with-parent-fail.yaml b/core/src/test/resources/flows/valids/flowable-with-parent-fail.yaml
new file mode 100644
index 0000000000..e5126089a9
--- /dev/null
+++ b/core/src/test/resources/flows/valids/flowable-with-parent-fail.yaml
@@ -0,0 +1,23 @@
+id: flowable-with-parent-fail
+namespace: io.kestra.tests
+
+tasks:
+  - id: vision
+    type: io.kestra.core.tasks.flows.EachParallel
+    tasks:
+      - id: metaseg_date
+        type: io.kestra.core.tasks.flows.EachParallel
+        tasks:
+          - id: if
+            type: io.kestra.core.tasks.flows.If
+            condition: "{{parents[0].taskrun.value == 'CUMULATIVE' and {% for entry in json(taskrun.value) %}{{ entry.key }}{% endfor %}== 'NEW_MONTH'}}"
+            then:
+              - id: when-true
+                type: io.kestra.core.tasks.log.Log
+                message: 'Condition was true'
+            else:
+              - id: when-false
+                type: io.kestra.core.tasks.log.Log
+                message: 'Condition was false'
+        value: "[{\"NEW_MONTH\":\"2018-01-01\"}]"
+    value: "[\"MONTHLY\", \"CUMULATIVE\"]"
\ No newline at end of file