Add on_kill() to DatabricksTaskBaseOperator to cancel runs on task kill - #69442
Conversation
|
Could The branch also contains two Drafted-by: Codex (GPT-5) |
93e6f14 to
88089a2
Compare
|
Thanks for the review! You're right —
Also added the regression test you suggested: parent run_id=1, The branch has also been squashed to a single commit to fix the |
14783eb to
79168b2
Compare
79168b2 to
feb6783
Compare
|
Thanks for the quick turnaround. I re-checked HEAD ( Confirmed fixed
Residual before this is readyBoth touched files drop the first two lines of the standard ASF license header: Please restore the full header in:
Testing barNo live Databricks credentials/UI testing needed for merge. This matches how A rebase onto current Logic otherwise looks good from my side. |
9af8024 to
7790249
Compare
|
Rebased onto current main and fixed the missing license header. Branch is now a single commit on top of |
DatabricksSubmitRunOperator and DatabricksRunNowOperator both implement on_kill() to cancel the Databricks run when an Airflow task is killed (SIGTERM or execution_timeout). DatabricksTaskBaseOperator — the base for DatabricksTaskOperator and DatabricksNotebookOperator — was missing the same implementation, leaving Databricks jobs running after the Airflow task was killed and orphaning compute resources. DatabricksWorkflowTaskGroup received on_kill() in apache#42115; this PR closes the remaining gap for standalone task operators. For workflow members self.databricks_run_id is the shared parent run ID; cancelling it would stop all sibling tasks. on_kill() therefore calls _get_current_databricks_task()["run_id"] to target only the current task's own child run, mirroring monitor_databricks_job. Standalone operators continue to cancel via self.databricks_run_id directly. If resolving the child run_id fails (API error, task_key mismatch), on_kill logs the exception and returns without cancelling anything — falling back to the parent run_id would stop sibling tasks, defeating the purpose. Unit tests cover: cancel called for standalone operator, no-op when databricks_run_id is None, workflow-member cancels child run (parent=1, child=999, asserts cancel_run(999)), and workflow-member where _get_current_databricks_task raises asserts cancel_run not called.
7790249 to
9bbe8d0
Compare
|
cc @moomindani for Databricks team review |
moomindani
left a comment
There was a problem hiding this comment.
LGTM. I verified the run-id semantics both against internal Databricks documentation and empirically on a live workspace, because that is the crux of the original objection about cancelling the shared parent run.
Docs: the Jobs CLI/API reference states runs/cancel "Cancels a job run or a task run", so passing a child task run id is a supported operation, not an accident that happens to work. The internal Jobs Task API design doc confirms the id model — job_run_id is the parent, and multitask runs have multiple task runs grouped under it.
Empirically, with a two-task job running both tasks concurrently:
| Action | task_a |
task_b |
parent run |
|---|---|---|---|
cancel task_a's child run (post-fix) |
TERMINATED/CANCELED | still RUNNING | RUNNING |
| cancel the parent run (pre-fix) | CANCELED | CANCELED | CANCELED |
So that concern was exactly right, and the fix does what it claims: a killed Airflow task now cancels only its own Databricks task run and leaves siblings alone. Cancelling the parent really does take the siblings down with it.
The rest checks out: on_kill sits on DatabricksTaskBaseOperator so both DatabricksTaskOperator and DatabricksNotebookOperator inherit it, it mirrors monitor_databricks_job's _get_current_databricks_task()["run_id"] pattern, and refusing to fall back to the parent id on resolution failure is the right call — that fallback is precisely the sibling-cancellation I measured. 204 tests pass in the file, prek --stage pre-commit clean.
One thing worth recording rather than changing: in deferrable mode this on_kill does not fire, since the operator has left the worker by then. That is not a gap — DatabricksExecutionTrigger has its own async on_kill, and monitor_databricks_job defers with run_id=current_task_run_id, i.e. the child run, so the deferred path cancels the correct run too. Both paths are covered.
Drafted-by: Claude Code (Opus 5)
Summary
DatabricksSubmitRunOperatorandDatabricksRunNowOperatorboth implementon_kill()to cancel the Databricks run when an Airflow task is killed (SIGTERM orexecution_timeout).DatabricksTaskBaseOperator— the base forDatabricksTaskOperatorandDatabricksNotebookOperator— is missing the same implementation, so Databricks jobs continue running after the Airflow task is killed, orphaning compute resources and incurring unnecessary cloud spend.DatabricksWorkflowTaskGroupreceivedon_kill()in #42115; this PR closes the remaining gap for standalone task operators.Changes
on_kill()toDatabricksTaskBaseOperatorusingself.databricks_run_id, which is:Nonein__init__(noAttributeErrorrisk)_launch_job()the moment the run is submitted — earlier than any polling or permission callsTesting
Was generative AI tooling used to co-author this PR?