Eason09053360 opened a new pull request, #72656:
URL: https://github.com/apache/airflow/pull/72656
Airflow 3 allows Dag runs to have no logical date — runs triggered manually
from the UI and asset-triggered runs both store `NULL`. The helper behind
`airflow tasks test` and `DAG.test()` was written when a logical date was
always present, and treats an absent one as "match anything" in two places.
**1. The collision lookup deletes an unrelated run.**
`get_or_create_dagrun` replaces any run occupying the logical date it is
about
to use, because `(dag_id, logical_date)` is unique. The lookup compares with
`==`, which SQLAlchemy renders as `IS NULL` for a missing date, so a dateless
test picks an arbitrary dateless run and deletes it. `DagRun.task_instances`
cascades, so the run's task instances go with it.
Testing one task can therefore destroy a run a user triggered from the UI.
NULL dates never collide under a unique constraint, so there is nothing to
replace in that case and the lookup is now skipped.
**2. The pre-test clear resets every run's task instances.**
`DAG.test()` clears existing task instances before running by passing the
logical date as both bounds to `clear_dags`. Those bounds are applied under
`if start_date:` / `if end_date:`, so a `None` drops both and the query
reduces to `TaskInstance.dag_id == <dag_id>` — every run of the Dag.
Verified against an unrelated finished run: its task instance went from
`success` to `None` while the run itself still read `success`. Fixing only
the first issue would have left the runs alive with their history destroyed,
so the clear is guarded the same way.
Both fixes are the same one-line shape, and each has a regression test that
fails without it.
##### Notes for reviewers
- `session.commit()` in the helper became `session.flush()`. The line moves
in
this diff and `airflow-core` forbids a callee committing a session it was
handed. It is also safer: the delete now rolls back with the caller if the
subsequent create fails. It cannot affect visibility of the new run, since
it ran *before* the run was created.
- Repeated dateless `dag.test()` calls now accumulate runs instead of each
one
deleting the last. That is the intended cost — the old sweep was just as
likely to delete the user's own dateless run, which is the bug being fixed.
- `airflow dags test --logical-date <D>` still replaces a real run sitting at
`D`. That is a genuine collision under the unique constraint and the
documented behaviour of the helper, so it is deliberately left alone.
- For a non-`None` date the `clear_dags` call is arguably redundant, since
the
run it clears is deleted (and cascaded) on the next statement. It is
guarded
rather than removed, to keep this PR to one story; removing it is a
separate
cleanup worth discussing on its own.
---
##### Was generative AI tooling used to co-author this PR?
- [X] Yes — Claude Code (Opus 5)
Generated-by: Claude Code (Opus 5) following [the
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]