Skip to content

Validate a serialized Dag and fill its unset settings from the Airflow config - #74041

Merged
jason810496 merged 10 commits into
mainfrom
jason/lang-sdk-e2e/03b-serialized-dag-validation
Oct 5, 2026
Merged

jason810496 merged 10 commits into
mainfrom
jason/lang-sdk-e2e/03b-serialized-dag-validation

Conversation

@jason810496

@jason810496 jason810496 commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Stack (bottom to top): #74041, #74042, #74035, #74043, #74036, #74037, #73845, #73846, #73847

Why

A Lang-SDK runtime returns its Dags already serialized, so Airflow has to check them and fill what the runtime cannot know before storing them.

What changes

  • DagSerialization.validate_serialized_dag(data) checks a serialized Dag against the JSON schema, rejects duplicate task ids, checks max_active_runs, catchup and cycles as the SDK does, and returns the loaded SerializedDAG.
  • DagSerialization.fill_config_defaults(data) fills an unset max_active_tasks, max_active_runs, max_consecutive_failed_dag_runs, catchup and disable_bundle_versioning from [core] max_active_tasks_per_dag, [core] max_active_runs_per_dag, [core] max_consecutive_failed_dag_runs_per_dag, [scheduler] catchup_by_default and [dag_processor] disable_bundle_versioning, as a Python Dag does. A value the Dag sets is kept.
  • The field table of airflow-core/adr/lang-sdk/0004-dag-parsing.md says Airflow fills an unset field from its config.
DagSerialization.fill_config_defaults(data)
dag = DagSerialization.validate_serialized_dag(data)  # raises DeserializationError

Was generative AI tooling used to co-author this PR?

Comment thread airflow-core/src/airflow/serialization/serialized_objects.py
Comment thread airflow-core/src/airflow/serialization/serialized_objects.py
Comment thread airflow-core/src/airflow/serialization/serialized_objects.py
Comment thread airflow-core/src/airflow/serialization/serialized_objects.py Outdated
Comment thread airflow-core/src/airflow/serialization/serialized_objects.py Outdated
Comment thread airflow-core/adr/lang-sdk/0004-dag-parsing.md
Comment thread airflow-core/tests/unit/serialization/test_dag_serialization.py
@jason810496
jason810496 force-pushed the jason/lang-sdk-e2e/03b-serialized-dag-validation branch 2 times, most recently from 3570480 to ad14011 Compare October 2, 2026 04:07

@pierrejeambrun pierrejeambrun left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need prek run sync-go-sdk-schemas --hook-stage manual ? (I checked the code and not automatically syncing Java and Go schemas seems deliberate because it need a maintainer decision, but the CI doesn't warn about it and its really easy to miss the step).

I'll open a PR so at least the drift is caught so the author is asked to take a look instead of silently failing. Maybe something like #74091

LGTM beside kaxil comment and 1 suggestion as well.

Comment thread airflow-core/src/airflow/serialization/schema.json
@jason810496

Copy link
Copy Markdown
Member Author

Do we need prek run sync-go-sdk-schemas --hook-stage manual ? (I checked the code and not automatically syncing Java and Go schemas seems deliberate because it need a maintainer decision, but the CI doesn't warn about it and its really easy to miss the step).

I'll open a PR so at least the drift is caught so the author is asked to take a look instead of silently failing.

Actually, I just noted down the ideal solution to prevent the schema drift in a proper way in #74047 (comment). TL;DR; having bi-weekly job to notify us there's a drift between the Python source and the vendored one.

Yes, I will run the prek run sync-go-sdk-schemas --hook-stage manual

@jason810496
jason810496 force-pushed the jason/lang-sdk-e2e/03b-serialized-dag-validation branch from 0afbeb1 to c930dd6 Compare October 2, 2026 14:07

@jason810496 jason810496 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review

Comment thread airflow-core/src/airflow/serialization/serialized_objects.py
Comment thread airflow-core/src/airflow/serialization/serialized_objects.py
Comment thread airflow-core/src/airflow/serialization/serialized_objects.py
Comment thread airflow-core/src/airflow/serialization/serialized_objects.py Outdated
Comment thread airflow-core/src/airflow/serialization/serialized_objects.py Outdated
Comment thread airflow-core/adr/lang-sdk/0004-dag-parsing.md
Comment thread airflow-core/tests/unit/serialization/test_dag_serialization.py
Comment thread airflow-core/src/airflow/serialization/schema.json
Base automatically changed from jason/lang-sdk-e2e/03a-dag-processor-base to main October 2, 2026 15:09
@jason810496
jason810496 force-pushed the jason/lang-sdk-e2e/03b-serialized-dag-validation branch from c930dd6 to a07d7ad Compare October 2, 2026 15:09
Comment thread airflow-core/src/airflow/serialization/serialized_objects.py Outdated
Comment thread airflow-core/src/airflow/serialization/serialized_objects.py Outdated
Comment thread airflow-core/tests/unit/serialization/test_dag_serialization.py Outdated
DagSerialization.validate_serialized_dag checks the JSON schema,
deserializes a copy and looks for a cycle in the task graph. It raises
DeserializationError naming the Dag, and for a cycle a task on it. It is
meant for a serialized Dag that no Python code built, such as one a
Lang-SDK runtime returns, so the Python SDK's cycle check never ran on
it. The cycle check runs the shared detect_cycle over the serialized
downstream edges.
A Lang-SDK runtime cannot read the Airflow config, so it leaves out the
Dag settings that a Python Dag reads from it when unset. The new
DagSerialization.fill_config_defaults fills max_active_tasks,
max_active_runs, max_consecutive_failed_dag_runs, catchup and
disable_bundle_versioning in a serialized Dag from the config. A value
the Dag sets is kept.
The schema put additionalProperties on the tasks array, which JSON
Schema ignores, so a task entry like {} passed validation. Each entry
must now be an operator with a string task_id, and
validate_serialized_dag rejects a repeated task id. A schema error
now names the failing field's path.

Also pin both boolean config defaults to different values in the
fill_config_defaults tests, and cover the unwrapped cause of a
deserialization error.
receive() now calls DagSerialization.fill_config_defaults and
validate_serialized_dag, so the conformance job runs the same checks
as the Dag processor and the config-backed field list lives in one
place.
These tests passed the dag_maker proxy of the serialized Dag to
LazyDeserializedDAG.from_dag, which serialized each task as its repr.
The tasks schema now rejects that, so they serialize the SDK Dag.
validate_serialized_dag now applies the max_active_runs and catchup rules the
SDK Dag runs when it is built, to the Dag it deserializes. The cycle check
walks that Dag's tasks, so edges from the legacy _downstream_task_ids key and
from client_defaults count too. It returns the deserialized Dag.
@jason810496
jason810496 removed this pull request from stack #74044 October 3, 2026 17:58
@jason810496
jason810496 force-pushed the jason/lang-sdk-e2e/03b-serialized-dag-validation branch from a07d7ad to 962acf2 Compare October 3, 2026 17:58
@jason810496
jason810496 added this pull request to stack #74170 October 3, 2026 17:59
jsonschema 4.26 writes $.dag.tasks[2]['__type'] where 4.23 writes
$.dag.tasks[2].__type, so the import error and three tests changed with
the installed version. Build the path from the error's absolute path.
@jason810496
jason810496 force-pushed the jason/lang-sdk-e2e/03b-serialized-dag-validation branch from a729bf8 to a7efc7c Compare October 4, 2026 08:51

@jason810496 jason810496 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review!

Comment thread airflow-core/src/airflow/serialization/serialized_objects.py Outdated
Comment thread airflow-core/src/airflow/serialization/serialized_objects.py Outdated
Comment thread airflow-core/tests/unit/serialization/test_dag_serialization.py Outdated
@jason810496
jason810496 requested a review from kaxil October 4, 2026 08:57
@jason810496
jason810496 merged commit 1c3f78e into main Oct 5, 2026
189 of 190 checks passed
@jason810496
jason810496 deleted the jason/lang-sdk-e2e/03b-serialized-dag-validation branch October 5, 2026 03:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants