My first workflow
==================
In the previous example you made a simple workflow with two independent tasks
and learned how to run, unrun and handle conflicts. Now you are ready to build
your first more complex workflow with depending tasks and subworkflows.

Change to a new directory and initialize a tb repository.

.. tbinit:: my_first_workflow

.. tbshellcommand:: tb init

Make three simple tasks in `tasks.py`

.. tbfile:: tasks.py

.. literalinclude:: tasks.py

Now write the following workflow to a file `workflow.py`

.. tbfile:: workflow.py

.. literalinclude:: workflow.py

Notice that e.g. the task `plus_two` takes the output from the task `ok` as an input.

Run the workflow

.. tbshellcommand:: tb workflow workflow.py

Try ls

.. tbshellcommand:: tb ls

From the column `deps`, we can see that the task `ok` has all its
dependencies met and is ready to run, while the other tasks depend on `ok`.

We can now try to run only the task `ok`:

.. tbshellcommand:: tb run tree/ok

.. tbshellcommand:: tb ls

`ok` is now `done` and the dependencies to `might_fail1` and `plus_two` are'
fulfilled. The dependencies to `might_fail2` are still not met since it depends
on the task `plus_two`. However, since TaskBlaster keeps track of all
dependencies we can run all tasks in one go, and TaskBlaster will make sure
that they are executed in the correct order.

.. tbshellcommand:: tb run .

.. tbshellcommand:: tb ls

As expected all tasks except `might_fail2` succeeded. The reason for the
failure of `might_fail2` is clearly shown in the output of `tb ls`.

We will now add a subworkflow. To keep track of what we have done, make a new
file `workflow2.py` with the following code:

.. tbfile:: workflow2.py

.. literalinclude:: workflow2.py

There is now a new workflow called `SubWorkflow` with two input parameters and two
tasks. The main workflow class `Workflow` includes `SubWorkflow` as a
subworkflow. Let's run the workflow and see what happens

.. tbshellcommand:: tb workflow workflow2.py

.. tbshellcommand:: tb ls

Note that all tasks that belong to the subworkflow are located in the folder
`subwf`. Since the task `tree/subwf/ok2` depends on the failed task, it has the
state `cancel` and cannot be run. The other task is in the new state and can be
run directly.

.. tbshellcommand:: tb run .

.. tbshellcommand:: tb ls

Now all tasks except the failed task and its dependencies are `done`. Now let
us change the input to the workflow so that `tree/might_fail2` will pass. Copy
`workflow2.py` to a new file `workflow3.py` and change the input `max_num` to
the workflow.

.. tbfile:: workflow3.py

.. literalinclude:: workflow3.py
    :start-at: def workflow(runner):

Now run the workflow again

.. tbshellcommand:: tb workflow workflow3.py

Since we changed the input there is a conflict for the tasks `might_fail1` and
`might_fail2`. Let us keep the task `might_fail1` as it is and mark the
conflict as resolved

.. tbshellcommand:: tb resolve tree/might_fail1

In practice this means that the conflict state of this task will be changed to
`resolved`, so that we remember that we have seen the conflict and decided to
keep the original input parameters to the task. However, we unrun the failed
task

.. tbshellcommand:: tb unrun tree/might_fail2 --force

.. tbshellcommand:: tb ls -cscf

Now both the previously failed task and its dependencies have the state `new`.
We can now update the input to these tasks with the new input

.. tbshellcommand:: tb workflow workflow3.py

and run the tasks

.. tbshellcommand:: tb run .

Verify that all tasks are `done`

.. tbshellcommand:: tb ls

Finally we will see what happens when you unrun a task with descendants that
are `done`. Try to unrun the task `tree/plus_two`

.. tbshellcommand:: tb unrun tree/plus_two --force

.. tbshellcommand:: tb ls

As you can see the task `tree/plus_two` as well as all tasks that depend on it
were set to the `new` state.

You can run these tasks again

.. tbshellcommand:: tb run .

Try also to unrun the same task without using the flag `--force`. This is often
the safer option to use.

You have now completed your first realistic workflow!
