Workflow generator and for loops
Now we will investigate how to generate subworkflows in a loop. There are in principle two cases one can encounter:
The parameters that one wants to loop over are known and given by user input.
The parameters are determined from the result of another task.
Case 1 only requires a static workflow, while case 2 is dynamic in the sense that the tasks in the loop cannot be generated until the initial task that determines the parameters to loop over is done. Since an implementation that can handle the second case also can handle the first case all loops in TaskBlaster are dynamic. For-loops are implemented using the so called dynamic workflow generator
. Below we show a simple example:
Start by inititializing a TaskBlaster repo:
$ tb init
Created repository using module "taskblaster.repository" in "/home/myuser/tmprepo".
Make two simple tasks in tasks.py
:
def ok(number):
return number
def plus_two(number):
return [n for n in range(number + 2)]
Now we want to create a workflow that takes a number as input, and uses the task plus_two
to determine a list of numbers to loop over. The task ok
should then be executed for all numbers in the list.
First we add the task plus_two
to the file workflow.py
:
import taskblaster as tb
@tb.workflow
class Workflow:
number = tb.var()
@tb.task
def task1(self):
return tb.node('plus_two', number=self.number)
def workflow(runner):
runner.run_workflow(Workflow(number=1))
and run the workflow
$ tb workflow workflow.py entry: add new 0/0 tree/task1
$ tb run tree
Starting worker rank=000 size=001
[rank=000 2025-03-17 10:08:40 N/A-0/1] Worker class: —
[rank=000 2025-03-17 10:08:40 N/A-0/1] Required tags: —
[rank=000 2025-03-17 10:08:40 N/A-0/1] Supported tags: —
[rank=000 2025-03-17 10:08:40 N/A-0/1] name: None
tags: —
required_tags: —
resources: None
max_tasks: None
subworker_size: None
subworker_count: None
wall_time: None
[rank=000 2025-03-17 10:08:40 N/A-0/1] Main loop
[rank=000 2025-03-17 10:08:40 N/A-0/1] Running task1 ...
[rank=000 2025-03-17 10:08:40 N/A-0/1] Task task1 finished in 0:00:00.001452
[rank=000 2025-03-17 10:08:40 N/A-0/1] No available tasks, end worker main loop
Verify using tb view
that you have the expected output from the task.
$ tb view .
name: task1
location: /home/myuser/tmprepo/tree/task1
state: done
target: plus_two(…)
wait for: 0 dependencies
depth: 0
source workflow: <root workflow>
frozen by: (not frozen)
latest handled inputs:
None
handlers:
[]
handler data:
<None>
parents:
<task has no dependencies>
input:
["plus_two", {"number": 1}]
output:
[0, 1, 2]
Run information:
Worker name: N/A-0/1
Start time: 2025-03-17 10:08:40
End time: 2025-03-17 10:08:40
Duration: 0:00:00
Error: None
No custom actions defined for this task.
Now you are ready to add the loop. Add the following to the workflow.py
file and save it to a new file workflow2.py
.
import taskblaster as tb
@tb.workflow
class Workflow:
number = tb.var()
@tb.task
def task1(self):
return tb.node('plus_two', number=self.number)
@tb.dynamical_workflow_generator({'results': '*/*'})
def generated_wfs(self):
return tb.node('generate_wfs_from_list', inputs=self.task1)
def workflow(runner):
runner.run_workflow(Workflow(number=1))
We have now added a dynamical_workflow_generator
to the workflow. This decorator takes an input argument which specifies how the result is collected.
The input argument is a dictionary where the keys corresponds to the name that will be given to the results task and the item is the path to the results
that will be collected by the results task. It is possible to specify any number of seperate results collections. Here we simply collect all results to the results task results
. The workflow generator returns a dynamical_workflow_generator_task
that needs to be specified in the tasks.py
file or alternatively imported from an external package.
In this tutorial we will for simplicitly just update the tasks.py
file, which is automatically imported by TaskBlaster, even though it is a bit unintuitive to have workflows in this file:
import taskblaster as tb
# -- first_part_start
def ok(number):
return number
def plus_two(number):
return [n for n in range(number + 2)]
# -- first_part_end
@tb.dynamical_workflow_generator_task
def generate_wfs_from_list(inputs):
for inp in inputs:
wf = SubWorkflow(number=inp)
name = f'wf_{inp}'
yield name, wf
@tb.workflow
class SubWorkflow:
number = tb.var()
@tb.task
def generated_task1(self):
return tb.node('ok', number=self.number)
@tb.task
def generated_task2(self):
return tb.node('ok', number=self.number)
You can notice that we added a dynamical_workflow_generator_task
with the name generate_wfs_from_list
. Since each generated subworkflow will be given a specific folder the workflow generator task
takes a list as input
loops over the list
Defines which workflow that should be generated and what input arguments it should have and saves it to the variable wf.
Defines a unique name for the subfolder for the generated workflow
Yields the name of the subfolder together with the wf.
This is a minimal example for how you can use a workflow generator, but in principle you can more advanced logic inside the function (e. g. yielding different subworkflows depending on the input arguments etc.). Finally we also need to define the workflow SubWorkflow
that should be generated. Here we have a simple workflow with two simple tasks, but it is possible to generate arbitrary complex workflows.
Now let’s see what happens when we run the workflow.
$ tb workflow workflow2.py entry: add new 1/1 tree/generated_wfs/init add new 0/? tree/generated_wfs/results entry: have done 0/0 tree/task1
$ tb ls state info tags worker time folder ──────── ────────── ─────────── ─────────── ─────────── ───────────────────────────── new 1/1 tree/generated_wfs/init new 0/? tree/generated_wfs/results done 0/0 N/A-0/1 00:00:00 tree/task1
As you can see two tasks were created, the initializer init
and the finalizer which we defined as results
.
Let’s try to run the initializer:
$ tb run tree/generated_wfs/init Starting worker rank=000 size=001 [rank=000 2025-03-17 10:08:41 N/A-0/1] Worker class: — [rank=000 2025-03-17 10:08:41 N/A-0/1] Required tags: — [rank=000 2025-03-17 10:08:41 N/A-0/1] Supported tags: — [rank=000 2025-03-17 10:08:41 N/A-0/1] name: None tags: — required_tags: — resources: None max_tasks: None subworker_size: None subworker_count: None wall_time: None [rank=000 2025-03-17 10:08:41 N/A-0/1] Main loop [rank=000 2025-03-17 10:08:41 N/A-0/1] Running generated_wfs/init ... entry: add new 0/1 tree/generated_wfs/wf_0/generated_task1 add new 0/1 tree/generated_wfs/wf_0/generated_task2 entry: add new 0/1 tree/generated_wfs/wf_1/generated_task1 add new 0/1 tree/generated_wfs/wf_1/generated_task2 entry: add new 0/1 tree/generated_wfs/wf_2/generated_task1 add new 0/1 tree/generated_wfs/wf_2/generated_task2 update new 0/7 tree/generated_wfs/results [rank=000 2025-03-17 10:08:41 N/A-0/1] Task generated_wfs/init finished in 0:00:00.014636 [rank=000 2025-03-17 10:08:41 N/A-0/1] No available tasks, end worker main loop
$ tb ls state info tags worker time folder ──────── ────────── ─────────── ─────────── ─────────── ───────────────────────────── done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/init new 1/7 tree/generated_wfs/results new 1/1 tree/generated_wfs/wf_0/generated_task1 new 1/1 tree/generated_wfs/wf_0/generated_task2 new 1/1 tree/generated_wfs/wf_1/generated_task1 new 1/1 tree/generated_wfs/wf_1/generated_task2 new 1/1 tree/generated_wfs/wf_2/generated_task1 new 1/1 tree/generated_wfs/wf_2/generated_task2 done 0/0 N/A-0/1 00:00:00 tree/task1
You can now see that three workflows were generated, each containing two tasks. The dependencies of the results task were also correctly updated to 0/6. We can now run the remaining tasks:
$ tb run tree
Starting worker rank=000 size=001
[rank=000 2025-03-17 10:08:41 N/A-0/1] Worker class: —
[rank=000 2025-03-17 10:08:41 N/A-0/1] Required tags: —
[rank=000 2025-03-17 10:08:41 N/A-0/1] Supported tags: —
[rank=000 2025-03-17 10:08:41 N/A-0/1] name: None
tags: —
required_tags: —
resources: None
max_tasks: None
subworker_size: None
subworker_count: None
wall_time: None
[rank=000 2025-03-17 10:08:41 N/A-0/1] Main loop
[rank=000 2025-03-17 10:08:41 N/A-0/1] Running generated_wfs/wf_0/generated_task1 ...
[rank=000 2025-03-17 10:08:41 N/A-0/1] Task generated_wfs/wf_0/generated_task1 finished in 0:00:00.001390
[rank=000 2025-03-17 10:08:41 N/A-0/1] Running generated_wfs/wf_0/generated_task2 ...
[rank=000 2025-03-17 10:08:41 N/A-0/1] Task generated_wfs/wf_0/generated_task2 finished in 0:00:00.000815
[rank=000 2025-03-17 10:08:41 N/A-0/1] Running generated_wfs/wf_1/generated_task1 ...
[rank=000 2025-03-17 10:08:41 N/A-0/1] Task generated_wfs/wf_1/generated_task1 finished in 0:00:00.000820
[rank=000 2025-03-17 10:08:41 N/A-0/1] Running generated_wfs/wf_2/generated_task2 ...
[rank=000 2025-03-17 10:08:41 N/A-0/1] Task generated_wfs/wf_2/generated_task2 finished in 0:00:00.000821
[rank=000 2025-03-17 10:08:41 N/A-0/1] Running generated_wfs/wf_2/generated_task1 ...
[rank=000 2025-03-17 10:08:41 N/A-0/1] Task generated_wfs/wf_2/generated_task1 finished in 0:00:00.000825
[rank=000 2025-03-17 10:08:41 N/A-0/1] Running generated_wfs/wf_1/generated_task2 ...
[rank=000 2025-03-17 10:08:41 N/A-0/1] Task generated_wfs/wf_1/generated_task2 finished in 0:00:00.001370
[rank=000 2025-03-17 10:08:41 N/A-0/1] Running generated_wfs/results ...
[rank=000 2025-03-17 10:08:41 N/A-0/1] Task generated_wfs/results finished in 0:00:00.000237
[rank=000 2025-03-17 10:08:41 N/A-0/1] No available tasks, end worker main loop
$ tb ls state info tags worker time folder ──────── ────────── ─────────── ─────────── ─────────── ───────────────────────────── done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/init done 7/7 N/A-0/1 00:00:00 tree/generated_wfs/results done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_0/generated_task1 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_0/generated_task2 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_1/generated_task1 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_1/generated_task2 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_2/generated_task1 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_2/generated_task2 done 0/0 N/A-0/1 00:00:00 tree/task1
As you can see all tasks are now in the state done
and you can view the results
$ tb view tree/generated_wfs/results
name: generated_wfs/results
location: /home/myuser/tmprepo/tree/generated_wfs/results
state: done
target: define(…)
wait for: 0 dependencies
depth: 3
source workflow: generated_wfs
frozen by: (not frozen)
latest handled inputs:
None
handlers:
[]
handler data:
<None>
parents:
generated_wfs/init
generated_wfs/wf_0/generated_task1
generated_wfs/wf_0/generated_task2
generated_wfs/wf_1/generated_task1
generated_wfs/wf_1/generated_task2
generated_wfs/wf_2/generated_task1
generated_wfs/wf_2/generated_task2
input:
["define", {"__tb_implicit__": [["generated_wfs/init", {"__tb_type__": "ref", "index": [], "name": "generated_wfs/init"}]], "obj": {"wf_0/generated_task1": {"__tb_type__": "ref", "index": [], "name": "generated_wfs/wf_0/generated_task1"}, "wf_0/generated_task2": {"__tb_type__": "ref", "index": [], "name": "generated_wfs/wf_0/generated_task2"}, "wf_1/generated_task1": {"__tb_type__": "ref", "index": [], "name": "generated_wfs/wf_1/generated_task1"}, "wf_1/generated_task2": {"__tb_type__": "ref", "index": [], "name": "generated_wfs/wf_1/generated_task2"}, "wf_2/generated_task1": {"__tb_type__": "ref", "index": [], "name": "generated_wfs/wf_2/generated_task1"}, "wf_2/generated_task2": {"__tb_type__": "ref", "index": [], "name": "generated_wfs/wf_2/generated_task2"}}}]
output:
{'wf_0/generated_task1': 0, 'wf_0/generated_task2': 0, 'wf_1/generated_task1': 1, 'wf_1/generated_task2': 1, 'wf_2/generated_task1': 2, 'wf_2/generated_task2': 2}
Run information:
Worker name: N/A-0/1
Start time: 2025-03-17 10:08:41
End time: 2025-03-17 10:08:41
Duration: 0:00:00
Error: None
No custom actions defined for this task.
Running everything in a single go
In the previous example we did the calculations step by step. It is instructive to see what happens if we try to run everything
in a single go. First remove the tree using tb remove tree
or alternatively make a new repository in a new folder and copy the files
tasks.py
and workflow2.py
to the new folder:
$ tb remove tree --force
deleting: generated_wfs/results
deleting: generated_wfs/wf_2/generated_task2
deleting: generated_wfs/wf_1/generated_task1
deleting: generated_wfs/wf_0/generated_task1
deleting: generated_wfs/wf_0/generated_task2
deleting: generated_wfs/wf_1/generated_task2
deleting: generated_wfs/wf_2/generated_task1
deleting: generated_wfs/init
deleting: task1
9 task(s) were deleted.
Double check so that all tasks were removed
$ tb ls
state info tags worker time folder
──────── ────────── ─────────── ─────────── ─────────── ─────────────────────────────
Now run the workflow and then run all tasks
$ tb workflow workflow2.py entry: add new 0/0 tree/task1 add new 0/1 tree/generated_wfs/init add new 0/? tree/generated_wfs/results entry: have new 0/0 tree/task1
$ tb run tree Starting worker rank=000 size=001 [rank=000 2025-03-17 10:08:42 N/A-0/1] Worker class: — [rank=000 2025-03-17 10:08:42 N/A-0/1] Required tags: — [rank=000 2025-03-17 10:08:42 N/A-0/1] Supported tags: — [rank=000 2025-03-17 10:08:42 N/A-0/1] name: None tags: — required_tags: — resources: None max_tasks: None subworker_size: None subworker_count: None wall_time: None [rank=000 2025-03-17 10:08:42 N/A-0/1] Main loop [rank=000 2025-03-17 10:08:42 N/A-0/1] Running task1 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task task1 finished in 0:00:00.001382 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/init ... entry: add new 0/1 tree/generated_wfs/wf_0/generated_task1 add new 0/1 tree/generated_wfs/wf_0/generated_task2 entry: add new 0/1 tree/generated_wfs/wf_1/generated_task1 add new 0/1 tree/generated_wfs/wf_1/generated_task2 entry: add new 0/1 tree/generated_wfs/wf_2/generated_task1 add new 0/1 tree/generated_wfs/wf_2/generated_task2 update new 0/7 tree/generated_wfs/results [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/init finished in 0:00:00.014037 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_0/generated_task1 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_0/generated_task1 finished in 0:00:00.000803 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_1/generated_task2 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_1/generated_task2 finished in 0:00:00.001255 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_2/generated_task2 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_2/generated_task2 finished in 0:00:00.000748 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_0/generated_task2 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_0/generated_task2 finished in 0:00:00.000714 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_2/generated_task1 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_2/generated_task1 finished in 0:00:00.000764 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_1/generated_task1 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_1/generated_task1 finished in 0:00:00.000757 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/results ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/results finished in 0:00:00.000255 [rank=000 2025-03-17 10:08:42 N/A-0/1] No available tasks, end worker main loop
$ tb ls state info tags worker time folder ──────── ────────── ─────────── ─────────── ─────────── ───────────────────────────── done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/init done 7/7 N/A-0/1 00:00:00 tree/generated_wfs/results done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_0/generated_task1 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_0/generated_task2 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_1/generated_task1 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_1/generated_task2 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_2/generated_task1 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_2/generated_task2 done 0/0 N/A-0/1 00:00:00 tree/task1
As you can see all tasks were generated and run directly.
Using multiple finalizers
We will now see how to collect results from different tasks in different results tasks. First remove the tree:
$ tb remove tree --force
deleting: generated_wfs/results
deleting: generated_wfs/wf_2/generated_task1
deleting: generated_wfs/wf_1/generated_task2
deleting: generated_wfs/wf_2/generated_task2
deleting: generated_wfs/wf_0/generated_task1
deleting: generated_wfs/wf_0/generated_task2
deleting: generated_wfs/wf_1/generated_task1
deleting: generated_wfs/init
deleting: task1
9 task(s) were deleted.
Modify the input to the dynamical_workflow_generator
decorator in workflow2.py
and save to a new file workflow3.py
@tb.dynamical_workflow_generator(
{
'results': '*/*',
'results_task1': '*/generated_task1',
'results_task2': '*/generated_task2',
}
)
def generated_wfs(self):
return tb.node('generate_wfs_from_list', inputs=self.task1)
We have now defined three seperate finalizers, one pointing to all generated tasks, and two pointing to generated_task1 and generated_task_2 respectively. Run the workflow and run all tasks.
$ tb workflow workflow3.py entry: add new 0/0 tree/task1 add new 0/1 tree/generated_wfs/init add new 0/? tree/generated_wfs/results add new 0/? tree/generated_wfs/results_task1 add new 0/? tree/generated_wfs/results_task2 entry: have new 0/0 tree/task1
$ tb run tree Starting worker rank=000 size=001 [rank=000 2025-03-17 10:08:42 N/A-0/1] Worker class: — [rank=000 2025-03-17 10:08:42 N/A-0/1] Required tags: — [rank=000 2025-03-17 10:08:42 N/A-0/1] Supported tags: — [rank=000 2025-03-17 10:08:42 N/A-0/1] name: None tags: — required_tags: — resources: None max_tasks: None subworker_size: None subworker_count: None wall_time: None [rank=000 2025-03-17 10:08:42 N/A-0/1] Main loop [rank=000 2025-03-17 10:08:42 N/A-0/1] Running task1 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task task1 finished in 0:00:00.001409 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/init ... entry: add new 0/1 tree/generated_wfs/wf_0/generated_task1 add new 0/1 tree/generated_wfs/wf_0/generated_task2 entry: add new 0/1 tree/generated_wfs/wf_1/generated_task1 add new 0/1 tree/generated_wfs/wf_1/generated_task2 entry: add new 0/1 tree/generated_wfs/wf_2/generated_task1 add new 0/1 tree/generated_wfs/wf_2/generated_task2 update new 0/7 tree/generated_wfs/results update new 0/4 tree/generated_wfs/results_task1 update new 0/4 tree/generated_wfs/results_task2 [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/init finished in 0:00:00.015194 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_1/generated_task1 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_1/generated_task1 finished in 0:00:00.001123 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_0/generated_task2 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_0/generated_task2 finished in 0:00:00.000742 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_2/generated_task1 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_2/generated_task1 finished in 0:00:00.000758 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_2/generated_task2 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_2/generated_task2 finished in 0:00:00.000769 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_0/generated_task1 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_0/generated_task1 finished in 0:00:00.000753 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/wf_1/generated_task2 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/wf_1/generated_task2 finished in 0:00:00.000778 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/results ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/results finished in 0:00:00.000226 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/results_task1 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/results_task1 finished in 0:00:00.000259 [rank=000 2025-03-17 10:08:42 N/A-0/1] Running generated_wfs/results_task2 ... [rank=000 2025-03-17 10:08:42 N/A-0/1] Task generated_wfs/results_task2 finished in 0:00:00.000251 [rank=000 2025-03-17 10:08:42 N/A-0/1] No available tasks, end worker main loop
$ tb ls state info tags worker time folder ──────── ────────── ─────────── ─────────── ─────────── ───────────────────────────── done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/init done 7/7 N/A-0/1 00:00:00 tree/generated_wfs/results done 4/4 N/A-0/1 00:00:00 tree/generated_wfs/results_task1 done 4/4 N/A-0/1 00:00:00 tree/generated_wfs/results_task2 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_0/generated_task1 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_0/generated_task2 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_1/generated_task1 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_1/generated_task2 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_2/generated_task1 done 1/1 N/A-0/1 00:00:00 tree/generated_wfs/wf_2/generated_task2 done 0/0 N/A-0/1 00:00:00 tree/task1
You can view the new results tasks using tb view
$ tb view tree/generated_wfs/results_task1
name: generated_wfs/results_task1
location: /home/myuser/tmprepo/tree/generated_wfs/results_task1
state: done
target: define(…)
wait for: 0 dependencies
depth: 3
source workflow: generated_wfs
frozen by: (not frozen)
latest handled inputs:
None
handlers:
[]
handler data:
<None>
parents:
generated_wfs/init
generated_wfs/wf_0/generated_task1
generated_wfs/wf_1/generated_task1
generated_wfs/wf_2/generated_task1
input:
["define", {"__tb_implicit__": [["generated_wfs/init", {"__tb_type__": "ref", "index": [], "name": "generated_wfs/init"}]], "obj": {"wf_0/generated_task1": {"__tb_type__": "ref", "index": [], "name": "generated_wfs/wf_0/generated_task1"}, "wf_1/generated_task1": {"__tb_type__": "ref", "index": [], "name": "generated_wfs/wf_1/generated_task1"}, "wf_2/generated_task1": {"__tb_type__": "ref", "index": [], "name": "generated_wfs/wf_2/generated_task1"}}}]
output:
{'wf_0/generated_task1': 0, 'wf_1/generated_task1': 1, 'wf_2/generated_task1': 2}
Run information:
Worker name: N/A-0/1
Start time: 2025-03-17 10:08:42
End time: 2025-03-17 10:08:42
Duration: 0:00:00
Error: None
No custom actions defined for this task.
As you can see the finalizer results_task1 only points to the output of the tasks generated_task1
etc.