Make deadline reads and serialization robust to dynamic/malformed intervals - #68919
Conversation
12a8e11 to
352702c
Compare
352702c to
31bd6d5
Compare
There was a problem hiding this comment.
Thanks for the PR.
I would make the code less verbose and keep only relevant comments/pieces. There are too many big comments some of them needs to be removed completely, some of them needs to be trimmed.
Overall looking good, just a few suggestions.
Another pair of eyes would be great on this.
31bd6d5 to
1901333
Compare
6daac55 to
4a0ae29
Compare
pierrejeambrun
left a comment
There was a problem hiding this comment.
Some changes doesn't seem related / necessary for fixing the related issue.
Can you keep the change as minimal as possible (for the issue we are trying to solve) and separate the rest in another extra PR.
Basically only those seems related:
M airflow-core/src/airflow/api_fastapi/core_api/datamodels/ui/deadline.py
M airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml
M airflow-core/src/airflow/api_fastapi/core_api/routes/ui/deadlines.py
M airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_deadlines.py…ervals Hardens the read and (de)serialization paths for deadline alerts so dynamic (``VariableInterval``) and malformed stored data no longer break the UI/API. - UI deadline-alert response: ``DeadlineAlert.interval`` is a JSON column holding the Airflow-serialized interval, not a plain number. Coerce it to seconds for a fixed ``timedelta`` and to ``None`` for a dynamic ``VariableInterval`` (resolved later by the scheduler), instead of letting Pydantic 500 on the dict. The ``interval`` field becomes ``float | None``. - Drop ``interval`` from the sortable columns of the deadline-alerts endpoint: ordering by a JSON column sorts by structure/text, not duration, so the result was arbitrary and misleading. - Deserialization: route by the encoder-stamped ``__class_path`` ahead of the ``reference_type`` name (a custom reference may share a class name with a builtin), and raise a clear error for a reference with no importable ``__class_path`` instead of an opaque ``KeyError``. - ``Deadline.__repr__`` / ``DeadlineAlert.__repr__`` no longer raise: guard the ``dagrun`` relationship (the FK can be set while the relationship is None after a cascade delete) and handle the dict-shaped JSON interval. A ``__repr__`` must never raise. - ``prune_deadlines`` explicitly excludes deadlines already marked ``missed`` so a missed deadline (whose callback is owned by the scheduler/triggerer) and its queued callback are never cascade-deleted. Generated-by: Claude Code (Opus via Claude Code) on behalf of Sean Ghaeli
The sort-key comment restated a constraint already covered by test_order_by_interval_is_rejected; the __class_path comment restated the ValueError message right below it. Generated-by: Claude Code (Opus)
Per review: keep only the interval coercion, order_by removal, and their tests; move repr guards, decoder routing, and prune guard to a follow-up.
4a0ae29 to
ebd49cd
Compare
|
Hi @pierrejeambrun I've split up the PR so that this one just addresses #69245 |
Backport successfully created: v3-3-testNote: As of Merging PRs targeted for Airflow 3.X In matter of doubt please ask in #release-management Slack channel.
|
|
Please note #70637 |
|
@shahar1 taking a look |
Split out of apache#68919 per review: decoder __class_path routing, clear error for missing __class_path, repr guards for severed dagrun and dict-shaped interval, and prune guard for missed deadlines.
apache#68919 changed _private_ui.yaml without regenerating the TypeScript client and CI stayed green: selective checks decide whether to skip the ts-compile-lint-* hooks from file groups that do not cover the UI codegen input specs, while the hooks themselves trigger on any yaml under the openapi directories. The stale client then masked a type error that broke main for every PR running full static checks. The same gap applied to v2-simple-auth-manager-generated.yaml, so a spec-only change also skipped the simple auth manager UI hook. Track the codegen-input specs in their own file group so spec-only changes run the UI hooks without forcing the full test matrix, and drop the main UI hook trigger for the simple auth manager spec: that pattern was copied in when the hook was created (apache#51725), a month after the spec was renamed v1 to v2 (apache#50705), so it has never matched a file - apache#53636 fixed the sibling hook's copy but missed this one. The main UI codegen does not consume that spec either.
…alformed intervals (#68919) (#70625) * Make deadline reads and serialization robust to dynamic/malformed intervals Hardens the read and (de)serialization paths for deadline alerts so dynamic (``VariableInterval``) and malformed stored data no longer break the UI/API. - UI deadline-alert response: ``DeadlineAlert.interval`` is a JSON column holding the Airflow-serialized interval, not a plain number. Coerce it to seconds for a fixed ``timedelta`` and to ``None`` for a dynamic ``VariableInterval`` (resolved later by the scheduler), instead of letting Pydantic 500 on the dict. The ``interval`` field becomes ``float | None``. - Drop ``interval`` from the sortable columns of the deadline-alerts endpoint: ordering by a JSON column sorts by structure/text, not duration, so the result was arbitrary and misleading. - Deserialization: route by the encoder-stamped ``__class_path`` ahead of the ``reference_type`` name (a custom reference may share a class name with a builtin), and raise a clear error for a reference with no importable ``__class_path`` instead of an opaque ``KeyError``. - ``Deadline.__repr__`` / ``DeadlineAlert.__repr__`` no longer raise: guard the ``dagrun`` relationship (the FK can be set while the relationship is None after a cascade delete) and handle the dict-shaped JSON interval. A ``__repr__`` must never raise. - ``prune_deadlines`` explicitly excludes deadlines already marked ``missed`` so a missed deadline (whose callback is owned by the scheduler/triggerer) and its queued callback are never cascade-deleted. Generated-by: Claude Code (Opus via Claude Code) on behalf of Sean Ghaeli * Remove redundant comments in deadline sort/deserialize The sort-key comment restated a constraint already covered by test_order_by_interval_is_rejected; the __class_path comment restated the ValueError message right below it. Generated-by: Claude Code (Opus) * Trim PR to the UI deadlineAlerts 500 fix only Per review: keep only the interval coercion, order_by removal, and their tests; move repr guards, decoder routing, and prune guard to a follow-up. --------- (cherry picked from commit f840a82) Co-authored-by: Sean Ghaeli <58916776+seanghaeli@users.noreply.github.com> Co-authored-by: Sean Ghaeli <ghaeli@amazon.com>
#68919 changed _private_ui.yaml without regenerating the TypeScript client and CI stayed green: selective checks decide whether to skip the ts-compile-lint-* hooks from file groups that do not cover the UI codegen input specs, while the hooks themselves trigger on any yaml under the openapi directories. The stale client then masked a type error that broke main for every PR running full static checks. The same gap applied to v2-simple-auth-manager-generated.yaml, so a spec-only change also skipped the simple auth manager UI hook. Track the codegen-input specs in their own file group so spec-only changes run the UI hooks without forcing the full test matrix, and drop the main UI hook trigger for the simple auth manager spec: that pattern was copied in when the hook was created (#51725), a month after the spec was renamed v1 to v2 (#50705), so it has never matched a file - #53636 fixed the sibling hook's copy but missed this one. The main UI codegen does not consume that spec either.
…nges (#70643) #68919 changed _private_ui.yaml without regenerating the TypeScript client and CI stayed green: selective checks decide whether to skip the ts-compile-lint-* hooks from file groups that do not cover the UI codegen input specs, while the hooks themselves trigger on any yaml under the openapi directories. The stale client then masked a type error that broke main for every PR running full static checks. The same gap applied to v2-simple-auth-manager-generated.yaml, so a spec-only change also skipped the simple auth manager UI hook. Track the codegen-input specs in their own file group so spec-only changes run the UI hooks without forcing the full test matrix, and drop the main UI hook trigger for the simple auth manager spec: that pattern was copied in when the hook was created (#51725), a month after the spec was renamed v1 to v2 (#50705), so it has never matched a file - #53636 fixed the sibling hook's copy but missed this one. The main UI codegen does not consume that spec either. (cherry picked from commit b43a87e) Co-authored-by: Shahar Epstein <60007259+shahar1@users.noreply.github.com>
DeadlineAlert.intervalis a JSON column (serializedtimedeltaor dynamicVariableInterval), but the/ui/dags/{dag_id}/deadlineAlertsresponse declaredinterval: float— any alert with a dict-shaped interval failed validation and the endpoint returned 500, breaking the run-page deadline badge.Fix:
intervalbecomesfloat | Nonewith a validator (seconds for fixed intervals,Nonefor dynamic), andintervalis dropped fromorder_by(sorting a JSON column sorts by structure, not duration).Robustness fixes from earlier revisions split out to #70421 per review.
Closes: #69245