Join
A Join task is used in conjunction with a Fork Join or Dynamic Fork task to join all the tasks within the forks.
In the Fork/Join task, the Join task waits for a list of forked tasks to be completed before proceeding with the next task. However, when used with a Dynamic Fork task, it implicitly waits for all forked tasks to complete.
Task parameters
Configure these parameters for the Join task.
Parameter | Description | Required/ Optional |
---|---|---|
joinOn | A list of task reference names that the Join task will wait for completion before proceeding with the next task. | Required. |
expression | The join script, which controls how the Join task completes if specified. | Optional. |
Join script configuration
The join script is an optional configuration that will control how the join task completes. You can pass script parameters into the Join task’s inputParameters
. For the join script to work well, the forked tasks should be set as optional.
"inputParameters": {
"key": "value"
}
Example join script
(function(){
let results = {};
let pendingJoinsFound = false;
if($.joinOn){
$.joinOn.forEach((element)=>{
if($[element] && $[element].status !== 'COMPLETED'){
results[element] = $[element].status;
pendingJoinsFound = true;
}
});
if(pendingJoinsFound){
return {
"status":"IN_PROGRESS",
"reasonForIncompletion":"Pending",
"outputData":{
"scriptResults": results
}
};
}
// To complete the Join - return true OR an object with status = 'COMPLETED' like above.
return true;
}
})();
In the example script, there is a variable called $.joinOn
, which is an array containing the task references and output data of each joined task. The script is designed to check if the status of the tasks to be joined is COMPLETED. If any pending joins are found, the script changes the status of the pending join tasks to the required status (IN_PROGRESS in the example script).
The example script can be modified to suit your use case.
Task configuration
This is the task configuration for a Join task.
{
"name": "join",
"taskReferenceName": "join_ref",
"inputParameters": {},
"type": "JOIN",
"joinOn": [
// List of task reference names that the join should wait for
],
"expression": ""
}
Task output
The Join task output depends on whether a join script is used.
If no join script is used, the Join task will return a map where the keys are task reference names of the tasks being joined and the values are the corresponding outputs of those tasks. The tasks get joined by the order of completion.
If a join script is used, the Join task will also return the following parameters.
Parameter | Description |
---|---|
joinOn | A list of task reference names that the Join task will wait for completion before proceeding with the next task. |
Example output
- with no join script
- with join script
{
"taskReferenceName": {
"outputKey": "outputValue"
},
"anotherTaskReferenceName": {
"outputKey": "outputValue"
},
"someTaskReferenceName": {
"outputKey": "outputValue"
}
}
{
"joinOn": [
"taskReferenceName",
"anotherTaskReferenceName",
"someTaskReferenceName"
],
"taskReferenceName": {
"outputKey": "outputValue"
},
"anotherTaskReferenceName": {
"outputKey": "outputValue"
},
"someTaskReferenceName": {
"outputKey": "outputValue"
}
}
Configuring a Join task in UI
A Join task is automatically added whenever a Fork/Join task or a Dynamic Fork task is added.
To configure a Join task:
- In your workflow, select the Join task.
- In Input joins, select the forks that are required for joining.
- (Optional) Use a script to control how the Join task completes.
- In Join script, check Use scripting to determine join.
- Enter the script in the code box.
- If necessary, add the script parameters that will be passed into the Join task.
Examples
Here are some examples for using the Join task.
Join on all forks
In this example, the Join task waits for all forks to complete. The task will wait for the completion of my_task_ref_1
and my_task_ref_2
as specified by the joinOn
attribute.
// Join task definition
{
"name": "join_task",
"taskReferenceName": "my_join_task_ref",
"type": "JOIN",
"joinOn": [
"my_task_ref_1",
"my_task_ref_2"
]
}
Ignore one fork
In this example, the Fork task spawns three tasks, an email_notification task, an sms_notification task, and a http_notification task. Email and SMS are usually the best-effort delivery systems. However, in the case of an HTTP-based notification, you get a return code, and you can retry until it succeeds or eventually give up.
When you set up a notification workflow, you may decide to continue after sending an email and SMS notification. In that case, you can choose to joinOn those specific tasks only. Meanwhile, the http_notification task will continue to execute but will not block the rest of the workflow from proceeding.
// task definitions
[
{
"name": "fork_join",
"taskReferenceName": "my_fork_join_ref",
"type": "FORK_JOIN",
"forkTasks": [
[
{
"name": "email_notification",
"taskReferenceName": "email_notification_ref",
"type": "SIMPLE"
}
],
[
{
"name": "sms_notification",
"taskReferenceName": "sms_notification_ref",
"type": "SIMPLE"
}
],
[
{
"name": "http_notification",
"taskReferenceName": "http_notification_ref",
"type": "SIMPLE"
}
]
]
},
{
"name": "notification_join",
"taskReferenceName": "notification_join_ref",
"type": "JOIN",
"joinOn": [
"email_notification_ref",
"sms_notification_ref"
]
}
]
This is the output of notification_join. The output is a map, where the keys are the reference names of tasks being joined and the corresponding values are the outputs of those tasks.
// Join task output
{
"email_notification_ref": {
"email_sent_at": "2021-11-06T07:37:17+0000",
"email_sent_to": "test@example.com"
},
"sms_notification_ref": {
"sms_sent_at": "2021-11-06T07:37:17+0129",
"sms_sent_to": "+1-xxx-xxx-xxxx"
}
}
Example with a join script
Consider a Fork/Join task with two forks, each containing a sub-workflow.
Both forked tasks are marked as optional and the Join task is joined using the following join script.
(function(){
let results = {};
let pendingJoinsFound = false;
if($.joinOn){
$.joinOn.forEach((element)=>{
if($[element] && $[element].status !== 'COMPLETED'){
results[element] = $[element].status;
pendingJoinsFound = true;
}
});
if(pendingJoinsFound){
return {
"status":"IN_PROGRESS",
"reasonForIncompletion":"Pending",
"outputData":{
"scriptResults": results
}
};
}
return true; // To complete the join, return true OR an object with status = 'COMPLETED' like above.
}
})();
This script ensures that the Join task is completed only if all the forks are completed. If any pending joins are found, the script will return the Join task status to IN_PROGRESS. Only after the forked tasks are completed, then the script will complete the Join task.
If the workflow is run, you can see that the join has not been completed and is waiting for the second fork to complete. Based on the script, the join task will remain in the in-progress state until the pending joins are completed.
The join task is completed after the issue with the second forked task is fixed.