|
| 1 | +# Task Execution Model |
| 2 | + |
| 3 | +The task execution model can be confusing because several questions seem to arrive at |
| 4 | +once: is the task still current, should it run, and what happens to the recorded state? |
| 5 | + |
| 6 | +It becomes easier to follow once we stop looking at all of these questions at the same |
| 7 | +time and instead watch an ordinary task move through pytask. |
| 8 | + |
| 9 | +## The Normal Case |
| 10 | + |
| 11 | +In the normal case, a task passes through four phases: setup, execution, teardown, and |
| 12 | +processing the report. |
| 13 | + |
| 14 | +### Setup |
| 15 | + |
| 16 | +Setup is where pytask decides whether a task needs attention. |
| 17 | + |
| 18 | +It checks a few basic questions first. |
| 19 | + |
| 20 | +- Are all dependencies available and have they changed? |
| 21 | +- Do the products already exist and have they changed? |
| 22 | +- Has the task itself changed? |
| 23 | + |
| 24 | +Generally, change means whether the current state of a node matches the recorded state |
| 25 | +in the lockfile. For most filepath-based nodes, the state is the hash of the file |
| 26 | +content. |
| 27 | + |
| 28 | +If everything still matches the previously recorded state, the task is considered |
| 29 | +unchanged and pytask will not run it. |
| 30 | + |
| 31 | +If something does not match, the task is stale and pytask prepares to run it. |
| 32 | + |
| 33 | +### Execution |
| 34 | + |
| 35 | +Here pytask calls the task function itself. |
| 36 | + |
| 37 | +### Teardown |
| 38 | + |
| 39 | +Once the task function has returned, pytask checks whether the promised products are |
| 40 | +really there. |
| 41 | + |
| 42 | +This matters because a task can finish without raising an exception and still leave the |
| 43 | +project in an incomplete state. Teardown is where pytask notices that kind of mismatch. |
| 44 | + |
| 45 | +### Processing The Report |
| 46 | + |
| 47 | +After teardown, pytask knows the outcome of the task. In case the task succeeded, this |
| 48 | +is also the moment where pytask updates the recorded state for the task. |
| 49 | + |
| 50 | +## Exceptions to the Rule |
| 51 | + |
| 52 | +Not every task follows this path all the way through. |
| 53 | + |
| 54 | +Markers and runtime options can short-circuit parts of the model. A task can be skipped, |
| 55 | +persisted, or forced to run even when it would otherwise be left alone. |
| 56 | + |
| 57 | +### Skipping Tasks |
| 58 | + |
| 59 | +Sometimes a task and its subgraph should not run at all. This might be because the tasks |
| 60 | +are too costly, buggy, or irrelevant for the current run. |
| 61 | + |
| 62 | +For temporary exclusions, you would use the [`-m`](<>) or [`-k`](<>) options, maybe in |
| 63 | +combination with a `not ...` expression. |
| 64 | + |
| 65 | +For a permanent exclusion, you would use the |
| 66 | +[`@pytask.mark.skip`](../api/marks.md#pytask.mark.skip) or |
| 67 | +[`@pytask.mark.skipif`](../api/marks.md#pytask.mark.skipif) markers. |
| 68 | + |
| 69 | +Skipping hooks into setup because pytask should stop before execution starts. All |
| 70 | +dependent tasks are marked to be skipped as well. |
| 71 | + |
| 72 | +### Persisting Tasks |
| 73 | + |
| 74 | +Persisting is useful when a task would normally be considered stale, but rerunning it is |
| 75 | +not desirable. A common example is a change to the task file that does not change the |
| 76 | +actual result, such as formatting. |
| 77 | + |
| 78 | +Persisting also has to hook into setup because pytask needs to decide early that the |
| 79 | +task should not execute even though something changed. Later, when the report is |
| 80 | +processed, pytask accepts the current state as the new recorded state. |
| 81 | + |
| 82 | +Users can opt into this behavior with the |
| 83 | +[`persist`](../tutorials/making_tasks_persist.md) marker. The disadvantage of the |
| 84 | +decorator is that it is permanent and removing it triggers a rerun of the task. |
| 85 | + |
| 86 | +What is missing is a temporary option of the persisting mechanism that would also allow |
| 87 | +to integrate new or renamed tasks into an existing project without triggering a rerun. |
| 88 | + |
| 89 | +### Forcing Tasks to Run |
| 90 | + |
| 91 | +Sometimes the opposite is needed: a task should run even though pytask would otherwise |
| 92 | +consider it unchanged. |
| 93 | + |
| 94 | +This has to affect setup as well because setup is where pytask normally decides that an |
| 95 | +unchanged task can be left alone. Forcing a task to run overrides that decision and lets |
| 96 | +the task continue to execution. |
| 97 | + |
| 98 | +Users can request this behavior with the `--force` option. |
| 99 | + |
| 100 | +### Fine-grained Staleness Decision |
| 101 | + |
| 102 | +The current model mostly answers staleness as a yes-or-no question based on recorded |
| 103 | +state and the current state of the task, its dependencies, and its products. |
| 104 | + |
| 105 | +Issue [#403](https://github.com/pytask-dev/pytask/issues/403) explores whether this |
| 106 | +decision could become more fine-grained. For example, users might want to treat changes |
| 107 | +to the task source differently from changes to dependencies or products, or they might |
| 108 | +want to override the default decision for one run without changing the task itself. |
0 commit comments