conductor icon indicating copy to clipboard operation
conductor copied to clipboard

[Bug] Timeline UI goes blank when DO_WHILE loop contains SWITCH defaultCase or FORK_JOIN_DYNAMIC tasks

Open pinyiw opened this issue 6 months ago • 1 comments

Describe the bug When a DO_WHILE loop contains a SWITCH task (with execution entering the defaultCase) or FORK_JOIN_DYNAMIC tasks, the timeline view in the Conductor UI fails to render and appears blank.

Details Conductor version: v3.21.15 Persistence implementation: Postgres Queue implementation: Postgres Lock: Redis Workflow definition for SWITCH task:

{
  "createTime": 1750729588107,
  "updateTime": 1750729654933,
  "name": "TestWhileSwitchDefaultBug",
  "description": "Edit or extend this sample workflow. Set the workflow name to get started",
  "version": 1,
  "tasks": [
    {
      "name": "do_while_ref",
      "taskReferenceName": "do_while_ref",
      "inputParameters": {
        "loop_limit": 2
      },
      "type": "DO_WHILE",
      "decisionCases": {},
      "defaultCase": [],
      "forkTasks": [],
      "startDelay": 0,
      "joinOn": [],
      "optional": false,
      "defaultExclusiveJoinTask": [],
      "asyncComplete": false,
      "loopCondition": "(function () {if ($.do_while_ref['iteration'] < $.loop_limit) {return true;} return false;})();",
      "loopOver": [
        {
          "name": "switch_ref",
          "taskReferenceName": "switch_ref",
          "inputParameters": {
            "decision_case": "default"
          },
          "type": "SWITCH",
          "decisionCases": {
            "dummy": [
              {
                "name": "dummy_decision_ref",
                "taskReferenceName": "dummy_decision_ref",
                "inputParameters": {
                  "dummy": "true"
                },
                "type": "SET_VARIABLE",
                "decisionCases": {},
                "defaultCase": [],
                "forkTasks": [],
                "startDelay": 0,
                "joinOn": [],
                "optional": false,
                "defaultExclusiveJoinTask": [],
                "asyncComplete": false,
                "loopOver": [],
                "onStateChange": {},
                "permissive": false
              }
            ]
          },
          "defaultCase": [
            {
              "name": "dummy_default_ref",
              "taskReferenceName": "dummy_default_ref",
              "inputParameters": {
                "dummy": "true"
              },
              "type": "SET_VARIABLE",
              "decisionCases": {},
              "defaultCase": [],
              "forkTasks": [],
              "startDelay": 0,
              "joinOn": [],
              "optional": false,
              "defaultExclusiveJoinTask": [],
              "asyncComplete": false,
              "loopOver": [],
              "onStateChange": {},
              "permissive": false
            }
          ],
          "forkTasks": [],
          "startDelay": 0,
          "joinOn": [],
          "optional": false,
          "defaultExclusiveJoinTask": [],
          "asyncComplete": false,
          "loopOver": [],
          "evaluatorType": "value-param",
          "expression": "decision_case",
          "onStateChange": {},
          "permissive": false
        }
      ],
      "evaluatorType": "javascript",
      "onStateChange": {},
      "permissive": false
    }
  ],
  "inputParameters": [],
  "outputParameters": {},
  "schemaVersion": 2,
  "restartable": true,
  "workflowStatusListenerEnabled": false,
  "ownerEmail": "[email protected]",
  "timeoutPolicy": "ALERT_ONLY",
  "timeoutSeconds": 0,
  "variables": {},
  "inputTemplate": {},
  "enforceSchema": true
}

Workflow definition for FORK_JOIN_DYNAMIC task:

{
  "createTime": 1750729849968,
  "updateTime": 1750730116303,
  "name": "TestWhileForkJoinDynamicBug",
  "description": "Edit or extend this sample workflow. Set the workflow name to get started",
  "version": 1,
  "tasks": [
    {
      "name": "do_while_ref",
      "taskReferenceName": "do_while_ref",
      "inputParameters": {
        "loop_limit": 2
      },
      "type": "DO_WHILE",
      "decisionCases": {},
      "defaultCase": [],
      "forkTasks": [],
      "startDelay": 0,
      "joinOn": [],
      "optional": false,
      "defaultExclusiveJoinTask": [],
      "asyncComplete": false,
      "loopCondition": "(function () {if ($.do_while_ref['iteration'] < $.loop_limit) {return true;} return false;})();",
      "loopOver": [
        {
          "name": "prepare_fork_input_ref",
          "taskReferenceName": "prepare_fork_input_ref",
          "inputParameters": {
            "queryExpression": "[{dummy: true}, {dummy: false}]"
          },
          "type": "JSON_JQ_TRANSFORM",
          "decisionCases": {},
          "defaultCase": [],
          "forkTasks": [],
          "startDelay": 0,
          "joinOn": [],
          "optional": false,
          "defaultExclusiveJoinTask": [],
          "asyncComplete": false,
          "loopOver": [],
          "onStateChange": {},
          "permissive": false
        },
        {
          "name": "dynamic_fork_ref",
          "taskReferenceName": "dynamic_fork_ref",
          "inputParameters": {
            "forkTaskName": "dummy",
            "forkTaskType": "SET_VARIABLE",
            "forkTaskInputs": "${prepare_fork_input_ref.output.result}"
          },
          "type": "FORK_JOIN_DYNAMIC",
          "decisionCases": {},
          "dynamicForkTasksParam": "dynamicTasks",
          "dynamicForkTasksInputParamName": "dynamicTasksInput",
          "defaultCase": [],
          "forkTasks": [],
          "startDelay": 0,
          "joinOn": [],
          "optional": false,
          "defaultExclusiveJoinTask": [],
          "asyncComplete": false,
          "loopOver": [],
          "onStateChange": {},
          "permissive": false
        },
        {
          "name": "join_ref",
          "taskReferenceName": "join_ref",
          "inputParameters": {},
          "type": "JOIN",
          "decisionCases": {},
          "defaultCase": [],
          "forkTasks": [],
          "startDelay": 0,
          "joinOn": [],
          "optional": false,
          "defaultExclusiveJoinTask": [],
          "asyncComplete": false,
          "loopOver": [],
          "onStateChange": {},
          "permissive": false
        }
      ],
      "evaluatorType": "javascript",
      "onStateChange": {},
      "permissive": false
    }
  ],
  "inputParameters": [],
  "outputParameters": {},
  "schemaVersion": 2,
  "restartable": true,
  "workflowStatusListenerEnabled": false,
  "ownerEmail": "[email protected]",
  "timeoutPolicy": "ALERT_ONLY",
  "timeoutSeconds": 0,
  "variables": {},
  "inputTemplate": {},
  "enforceSchema": true
}

To Reproduce Steps to reproduce the behavior:

  1. Start a workflow execution with either of the workflows above (no input needed).
  2. Open the execution page.
  3. Click on the Timeline tab under the Tasks tab.
  4. The page will go blank.

Expected behavior The timeline UI should work correctly.

Screenshots SWITCH workflow execution

DYNAMIC_FORK_JOIN execution

pinyiw avatar Jun 24 '25 02:06 pinyiw

Hey @pinyiw thanks for bringing this up! @v1r3n added a commit related to this bug. I'll follow-up with him.

jeffbulltech avatar Jul 07 '25 16:07 jeffbulltech