Fix asset event partition_key breaking older Task SDK workers - #72327
Fix asset event partition_key breaking older Task SDK workers#72327neel-astro wants to merge 1 commit into
Conversation
|
Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contributors' Guide
|
cdc7ea8 to
2d70c73
Compare
2d70c73 to
6020a2e
Compare
| response = old_ver_client.get("/execution/dag-runs/test_dag_run_consumed_event/run1") | ||
|
|
||
| assert response.status_code == 200 | ||
| assert all("partition_key" not in event for event in response.json()["consumed_asset_events"]) |
There was a problem hiding this comment.
consumed_asset_events is always [] on this route: the handler runs a plain select(DagRunModel) with no joinedload, SessionDep is a fresh create_session(scoped=False) so the fixture's in-session append is not visible, and safe_extract_from_orm defaults the unloaded relationship. So this all(...) iterates nothing and would pass with the version gate deleted entirely. Same for the /previous test below. Asserting response.json()["consumed_asset_events"] == [] would pin the invariant that actually holds today, and would still fail loudly if a later change adds eager loading here.
Why
AssetEventDagRunReference.partition_keywas added in 3.3.0 (#69115) but registered under the already-released2026-04-06Execution API version. Cadwyn applies a version's downgrade instructions only for clients older than that version, so a client requesting exactly2026-04-06still receives the field.Task SDK 1.2.x (Airflow 3.2.x) speaks
2026-04-06, and itsAssetEventDagRunReferencehas nopartition_key, withextra="forbid". Every asset-triggered task run by a 3.2.x worker against a 3.3.x API server fails before it starts:The value is
null, so this affects every asset-triggered run, not just partitioned assets. The task dies at supervision start.Reading
partition_keyout of each released task-sdk wheel'sairflow/sdk/api/datamodels/_generated.py:AssetEventDagRunReferenceAssetEventDagRunReferenceis the only one of the five models inAddPartitionKeyFieldthat did not gain the field at2026-04-06.DagRun,AssetEventResponse,TriggerDAGRunPayloadandDagRunAssetReferenceall carry it in 1.2.0+, so their gating is correct and is left alone.What
Move the
AssetEventDagRunReference.partition_keyschema instruction and itsconsumed_asset_eventsresponse converter out ofv2026_04_06.pyinto a newAddConsumedAssetEventPartitionKeyFieldinv2026_06_30.py, matching how the siblingAddPartitionDateFieldhandlesDagRun.partition_date(also new in 3.3.0). The HEAD datamodel and the generated Task SDK models are unchanged.Both halves of the gate move together. The
schema(...).didnt_existinstruction drives the per-version OpenAPI document and the converter mutates the wire body, so leaving either behind would ship a spec that contradicts the response.Only
TIRunContextgets a converter, where the two siblings in the same file register three each.DagRun.safe_extract_from_ormdefaultsconsumed_asset_eventsto[]whenever the relationship is not already loaded, andPATCH /task-instances/{id}/runis the only route that loads it, so bareDagRunresponses never carry one. Two tests inversions/v2026_06_30/test_dag_runs.pypin that invariant so it fails loudly if a future change adds eager loading there.Tests
TestConsumedEventPartitionKeyBackwardCompatmoves to thev2026_06_30suite, whereold_ver_clientis pinned to exactly2026-04-06— the version Task SDK 1.2.x sends. In its previous home it ran at2025-11-05, older than the mis-placed gate, which is why this passed CI.Three assertions cover the three ways this can go wrong:
2026-04-06client gets the event-levelpartition_keystripped while the Dag-run-levelpartition_keysurvives, in one response (under-moving the gate)2026-06-30and a HEAD client both still receive it (over-moving the gate would silently break 1.3.x, which sends2026-06-30and carries the field)AssetEventDagRunReferencematches the wire body at both versions (moving only one half of the gate)Beyond the suite, the released 1.2.2
TIRunContext— the model that raised the traceback above — was loaded from its wheel and used to validate a real captured2026-04-06response body: it accepts the server's current output and still rejects it oncepartition_keyis re-injected. That checks response bytes against the real released client model; it is not a live 1.2.x worker running end to end.One pre-existing test fixture changed:
old_ver_clientinversions/v2026_06_30/test_task_instances.pymoved from2026-06-16to2026-04-06. This is behaviour-preserving —2026-06-16was never a registered version and resolved to the same bundle — and it aligns the module with its siblings in that directory, which already pin2026-04-06.Backport
3.3.0 and 3.3.1 are both released with this bug, so a
main-only fix does not help anyone currently affected. Requesting the 3.3.2 milestone.related: #69115
related: #71861 — that PR fixes a different class of gap in the same two files (missing registrations on the compat previous-run route and nested
created_dagruns). The two are semantically orthogonal, but both touchremove_partition_key_from_dag_run, so whichever merges second will conflict there. The resolution is to keep theconsumed_asset_eventsloop deleted and keep that PR's added converters; re-adding the loop alongside the newVersionChangeis a silent no-op that the test suite cannot detect.Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Opus 5) following the guidelines