With depends_on_past=True, a task waits for its own instance in the previous run to succeed. Use it when each day builds on the day before, such as a running total.
The cost is real. If one day fails, every later day waits until someone fixes it.
Setup and teardown tasks solve a different problem. Suppose a task creates a cluster, and a later task must delete it, even if the work fails:
Delete the cluster, even after a failureworked example
@task
def create_cluster():
print("cluster created")
@task
def work():
raise ValueError("work failed")
@task
def delete_cluster():
print("cluster deleted")
cc = create_cluster()
cc >> work() >> delete_cluster().as_teardown(setups=cc)
What happened
| task | state |
|---|
| create_cluster | success |
| work | failed |
| delete_cluster | success |
The cluster was deleted, and the run still ended as failed, because work failed.
With a normal task, delete_cluster would be upstream_failed, and the cluster would keep running and costing money.
Why not an all_done task? In our test, work failed, and an all_done clean-up after it succeeded. The whole run was then marked successful.
A teardown does not hide the failure like that. Also, clearing the work task clears its setup and teardown too.