Skip to content

Commit 373ce99

Browse files
committed
Feature: When merging data and workflowData from sub-jobs, allow top-level arrays to concatenate instead of replace.
1 parent b99becd commit 373ce99

4 files changed

Lines changed: 23 additions & 24 deletions

File tree

docs/plugins.md

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -339,33 +339,19 @@ To include arbitrary data output from your job, which will be automatically pass
339339

340340
The format of the `data` object is freeform, and can contain whatever content you want. Note that the above example is pretty-printed for display, but in practice all messages must be sent as single lines, so remember to compact your JSON when serializing it.
341341

342-
Note that if you send multiple messages containing `data`, the top-level data object properties are shallow-merged (the latter prevails on duplicate keys). Using this you can add data incrementally during a job run.
343-
344-
As an advanced option, you can also incrementally *append to arrays* inside the `data` object using this syntax:
342+
Note that if you send multiple messages containing `data` within the same job, the top-level data object properties are shallow-merged (the latter prevails on duplicate keys). Using this you can add data incrementally during a job run. Additionally, if you are overwriting a top-level array with another array, it will be *concatenated* instead of replaced. Example:
345343

346344
```json
347-
{
348-
"xy": 1,
349-
"push": {
350-
"data.arr": [0, 1, 2]
351-
}
352-
}
345+
{ "xy": 1, "data": { "arr": [0, 1, 2] } }
353346
```
354347

355-
This would append to an array named `arr` (it will be created if needed). You can use simple `dot.path.notation` to access any array deep inside the data object.
356-
357-
Then, if you sent an additional message with another `push` on the same array like this:
348+
Then later, in the same job:
358349

359350
```json
360-
{
361-
"xy": 1,
362-
"push": {
363-
"data.arr": [3, 4, 5]
364-
}
365-
}
351+
{ "xy": 1, "data": { "arr": [3, 4, 5] } }
366352
```
367353

368-
The `arr` array would grow accordingly, and contain all 6 elements upon job completion.
354+
This would end up with `[0, 1, 2, 3, 4, 5]` in the final `arr` data array when the job completes.
369355

370356
##### Output Files
371357

@@ -487,9 +473,9 @@ To update the [Workflow Data](workflows.md#sharing-data-between-all-nodes) for t
487473
}
488474
```
489475

490-
Note that the workflow data is shallow-merged, so you can specify a sparsely-populated object and it will only add / replace the included top-level properties. If your job outputs multiple messages with `workflowData` they are all shallow-merged together.
476+
Note that the workflow data is shallow-merged, so you can specify a sparsely-populated object and it will only add / replace the included top-level properties. If your job outputs multiple messages with `workflowData` they are all shallow-merged together. Additionally, top-level arrays are concatenated when merging.
491477

492-
The workflow data is only updated when the job completes.
478+
The workflow data is only updated in the parent workflow when the sub-job completes.
493479

494480
### Action Plugins
495481

docs/workflows.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ xyOps offers another way to share data between nodes, including nodes that are n
206206
{ "xy": 1, "workflowData": { "foo": "bar" } }
207207
```
208208

209-
The data is shallow-merged into the shared `workflowData` object when the sub-job completes. Then, any subsequent jobs that launch from the same workflow are passed the updated `workflowData` object.
209+
The data is shallow-merged into the shared `workflowData` object when the sub-job completes (also, top-level arrays are concatenated together instead of replacing). Then, any subsequent jobs that launch from the same workflow are passed the updated `workflowData` object.
210210

211211
The `workflowData` object only lasts for the duration of the workflow run. It is not persistent like [Server User Data](servers.md#user-data), but it works in the same way.
212212

lib/util.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ class Util {
110110
return( Tools.digestHex(JSON.stringify(a)) != Tools.digestHex(JSON.stringify(b)) );
111111
}
112112

113+
mergeConcatInto(a, b) {
114+
// like Tools.mergeHashInto, but adds array concat
115+
for (var key in b) {
116+
if (Array.isArray(a[key]) && Array.isArray(b[key])) {
117+
a[key] = a[key].concat( b[key] );
118+
}
119+
else {
120+
a[key] = b[key];
121+
}
122+
}
123+
}
124+
113125
getDefaultUserPrivileges() {
114126
// get copy of default user privs, but remove any false keys
115127
var privs = Tools.copyHash( this.config.get('default_user_privileges') || {} );

lib/workflow.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,7 @@ class Workflows {
941941
details.wfJobData[sub_job.id] = overrides.input.data;
942942

943943
// merge in workflowData from sub job
944-
Tools.mergeHashInto( details.workflowData, sub_job.workflowData || {} );
944+
this.mergeConcatInto( details.workflowData, sub_job.workflowData || {} );
945945

946946
// if job was retried, return now
947947
if (sub_job.retried) return;
@@ -1143,6 +1143,7 @@ class Workflows {
11431143

11441144
tickWorkflow(job) {
11451145
// see if workflow has anything going on, otherwise end it
1146+
var self = this;
11461147
var workflow = job.workflow;
11471148
var state = workflow.state;
11481149
var details = this.jobDetails[job.id];
@@ -1275,7 +1276,7 @@ class Workflows {
12751276
(jobs || []).forEach( function(stub) {
12761277
if (stub.retried) return; // ignore retries when bubbling up data
12771278
if (stub.files && stub.files.length) details.files = details.files.concat(stub.files);
1278-
if (details.wfJobData[stub.id]) Tools.mergeHashInto(details.data, details.wfJobData[stub.id]);
1279+
if (details.wfJobData[stub.id]) self.mergeConcatInto(details.data, details.wfJobData[stub.id]);
12791280
} );
12801281
} );
12811282

0 commit comments

Comments
 (0)