Skip to content

forkTaskJoin() generates JOIN with empty joinOn — join completes immediately without waiting for branches #135

Description

@nthmost-orkes

Summary

forkTaskJoin() creates a JOIN task with joinOn: [] (empty array). The Conductor
server's JOIN executor uses joinOn.stream().allMatch(...) to check if all listed tasks
are terminal — on an empty stream, allMatch short-circuits to true immediately,
so the JOIN transitions to COMPLETED without waiting for any fork branches.

Server baseline

Conductor 3.32.0-rc.9

Root cause

// forkJoin.ts:22
export const forkTaskJoin = (
  taskReferenceName: string,
  forkTasks: TaskDefTypes[],
  optional?: boolean
): [ForkJoinTaskDef, JoinTaskDef] => [
  forkTask(taskReferenceName, forkTasks),
  generateJoinTask({ name: `${taskReferenceName}_join`, optional }),
  //                 ^^^  no joinOn passed — defaults to []
];

generateJoinTask defaults to joinOn: []. The existing test (factory.test.ts:141)
explicitly asserts joinOn: [], locking in the broken behavior.

Live evidence

Tested against Conductor OSS 3.32.0-rc.9 with a 10-second WAIT task as the fork branch:

After 2 seconds:
  forkTaskJoin (joinOn=[])          → join=COMPLETED  wait_branch=IN_PROGRESS  ← BUG
  manual joinOn=['wait_branch']     → join=IN_PROGRESS  wait_branch=IN_PROGRESS  ← CORRECT

The JOIN with joinOn: [] reached COMPLETED while the fork branch was still running.

Impact

Any workflow that uses forkTaskJoin() will have a JOIN that completes immediately
when first evaluated. Fork branches continue running concurrently, but the downstream
workflow does not wait for them.

Proposed fix

Infer joinOn from the last task reference name in the fork branch:

export const forkTaskJoin = (
  taskReferenceName: string,
  forkTasks: TaskDefTypes[],
  optional?: boolean
): [ForkJoinTaskDef, JoinTaskDef] => {
  const joinOn = forkTasks.length > 0
    ? [forkTasks[forkTasks.length - 1].taskReferenceName]
    : [];
  return [
    forkTask(taskReferenceName, forkTasks),
    generateJoinTask({ name: `${taskReferenceName}_join`, joinOn, optional }),
  ];
};

factory.test.ts should also be updated to assert joinOn: ['forkTaskJoin'] (the last
task's ref name) rather than joinOn: [].

Related

Discovered during systematic SDK audit against Conductor OSS 3.32.0-rc.9.
The multi-branch limitation of forkTask() is separately tracked in #94.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions