Skip to content

Derive a mixed-language marker for Dags with task.stub - #71213

Open
jason810496 wants to merge 1 commit into
apache:mainfrom
jason810496:feature/lang-sdk/mixed-language-dag-flag
Open

Derive a mixed-language marker for Dags with task.stub#71213
jason810496 wants to merge 1 commit into
apache:mainfrom
jason810496:feature/lang-sdk/mixed-language-dag-flag

Conversation

@jason810496

@jason810496jason810496 commented Aug 6, 2026

Copy link
Copy Markdown
Member

Why

A Lang-SDK artifact can play two roles that a Dag processor must treat oppositely, and nothing in the serialized Dag tells them apart:

RoleWhere the Dag is definedWhat the artifact contributes
Mixed-language DagA Python file whose tasks are @task.stubOnly the task implementations
Native Lang-SDK DagThe Go/Java source itselfThe whole Dag

For a native Dag the processor parses the artifact and the result is persisted. For a mixed-language Dag it must persist nothing: the Python Dag carrying the @task.stub tasks already owns that dag_id, so persisting the Lang-SDK side too would give conflicts.

How

The new is_mixed_language_dag flag at Dag level solves the problem.

  • Only the Lang SDK Dag can explicitly set the is_mixed_language_dag flag at Dag level argument.
  • For the Python Dag side, the is_mixed_language_dag field is a compute attribute that if there's any StubOperator in the Dag, the property will be true.
  • The Task SDK DAG gains nothing, a Python Dag can never set the is_mixed_language_dag flag.

The further mixed language Dag processing flow will be like:

  • JavaDagImporter don't emit those Dag with is_mixed_language_dag=True by default.
  • PythonDagImporter -> for all Dags which is_mixed_language_dag=True (the flag will be on if there's StubOperator in the Dag) -> validate the corresponding Java Dag structure (via TI.queue -> Coordinator -> JavaDagImporter(discover_mixed_language_dags=True) -> Java Dag structure) -> raise import error if there's validation error
  • and don't persist the Java side Dag structure.

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

@jason810496jason810496 self-assigned this Aug 6, 2026
@jason810496
jason810496force-pushed the feature/lang-sdk/mixed-language-dag-flag branch 2 times, most recently from 68c208e to 8e0c2a4CompareAugust 6, 2026 06:06
@jason810496jason810496 removed the backport-to-v3-3-test Backport to v3-3-test label Aug 6, 2026
@jason810496jason810496 added this to the Airflow 3.4.0 milestone Aug 6, 2026
@jason810496
jason810496 marked this pull request as ready for review August 6, 2026 06:15
@jason810496jason810496 changed the title Let a serialized Dag declare it only backs a Python Dag's stub tasksDerive a mixed-language marker for Dags with task.stubAug 6, 2026
Comment threadtask-sdk/src/airflow/sdk/definitions/dag.py Outdated
@jason810496
jason810496 marked this pull request as draft August 7, 2026 10:03
@jason810496
jason810496force-pushed the feature/lang-sdk/mixed-language-dag-flag branch from 8e0c2a4 to 7c94df5CompareAugust 9, 2026 07:05
A Lang-SDK artifact can either define a Dag natively or only supply the
implementations behind a Python Dag's @task.stub tasks. A Dag processor has to
treat those oppositely, persisting the first and discarding the second since the
Python Dag already owns that dag_id, and nothing in the serialized Dag told them
apart.
The flag is derived, never authored: a Python Dag reports it from the presence of
stub tasks, and neither the constructor nor attribute assignment can set it, so a
Dag cannot claim to be mixed-language without actually holding one.
@jason810496
jason810496force-pushed the feature/lang-sdk/mixed-language-dag-flag branch from 7c94df5 to b1c7e11CompareAugust 12, 2026 08:05
@jason810496
jason810496 marked this pull request as ready for review August 13, 2026 03:36

@uranusjruranusjr 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.

I guess this is the best given the restrictions since those names need to be public, and we don’t want to rename the Task protocol.

Comment on lines +125 to +126
# Derived, never authored -- see ``DAG.is_mixed_language_dag``.
is_mixed_language_dag: bool = False

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.

When do we plan to actually use this? I wonder if a property similar to the SDK DAG class’s property is enough.

@uranusjr

Copy link
Copy Markdown
Member
  • Only the Lang SDK Dag can explicitly set the is_mixed_language_dag flag at Dag level argument.

This does not seem to be a part of the PR? Why are you putting this here? Even if it’s true, why is it the case?

@uranusjr

Copy link
Copy Markdown
Member

The PR description diverges A LOT from the implementation. In the future, I would suggest not putting this verbose information in the description. Use an issue instead, and when you update the PR, add comments to the issue to record the design changes timeline.

If you really do want to put this much stuff in the PR description, REMEMBER TO UPDATE IT. Tell Claude to do it, I don’t care, but you need to do it.

@jason810496

jason810496 commented Aug 17, 2026

Copy link
Copy Markdown
MemberAuthor

When do we plan to actually use this? I wonder if a property similar to the SDK DAG class’s property is enough.

When introducing the native Dag DSL. We have to introduce at "serialization Dag level" so the native Dag is able to set the flag. (native Dag DSL -> Serialized Dag JSON -> DagFileParsingResult -> LazyDeserializedDAG)

  • Only the Lang SDK Dag can explicitly set the is_mixed_language_dag flag at Dag level argument.

This does not seem to be a part of the PR? Why are you putting this here? Even if it’s true, why is it the case?

IMO, we need to define the spec first (which is the purpose of this PR) before wiring the native Dag part up.
If I don't explain how does the further native Dag <-> Airflow core Dag serialization works. The further reviewers don't know why do we need to introduce a new field at all.

@uranusjr

Copy link
Copy Markdown
Member

I think there are two issues. First of all, why does a language sdk dag need to define this at dag-level? From Airflow Core’s prespective, such a dag is essentially equivalent to a Python-defined dag that only contains stub tasks. Why can’t the dag processor just emit task-level markers?

Second, even if we accept a dag-level flag for this use case, is_mixed_language_dag is completely backwards. A Java dag that defines only Java tasks is entirely the opposite of “mixed” since there’s only Java.

@jason810496

Copy link
Copy Markdown
MemberAuthor

I think there are two issues. First of all, why does a language sdk dag need to define this at dag-level? From Airflow Core’s prespective, such a dag is essentially equivalent to a Python-defined dag that only contains stub tasks. Why can’t the dag processor just emit task-level markers?

Second, even if we accept a dag-level flag for this use case, is_mixed_language_dag is completely backwards. A Java dag that defines only Java tasks is entirely the opposite of “mixed” since there’s only Java.

The mixed Lang artifact is parseable once both #70805 (support optional DagBundle based deployment) and the DagImporter interface (JarImporter, able to get Dags from Jars) get merged.

Without the flag, consider the case where we place the Python Dag with stub operator in one DagBundle and the Jar artifact in another DagBundle, the DagModel will jump between mixed Lang Dag and native Dag. Since the Jar artifact for mixed Lang itself is also a valid native Dag Jar.

From my perspective, it's necessary to introduce the flag at the Dag-level to make the purpose explicit, so that the DagImporters are able to distinguish between the mixed Lang Jar and the native Dag Jar.

@Andrushika

Copy link
Copy Markdown
Contributor

Just want to clarify a higher-level design question... Will the Lang SDK support stub syntax in native Dags in the future? (e.g. a native Java Dag that holds a Python or Go task)
If not, please just ignore me.

If it is planned, I think the current flag may not cover that case. Right now the same boolean means two different things:

  1. On a Python Dag it is derived, and it means “this Dag has stub tasks”.
  2. On a Lang-SDK Dag the producer sets it, and it means “this Dag is implementation-only, do not persist it” (if I read the planned flow right).

A native Dag with stub tasks would hit both meanings at once. It has stub tasks, but it is also the real definition that should be persisted. Setting the flag to true would get it dropped, so it has no way to mark itself.

If that case is planned, I would suggest a separate field such as definition_role (primary / implementation_only). Then this flag keeps one meaning only (“has stub tasks”), and the persist decision reads the role instead.

Just a small suggestion and I could be completely wrong. Thanks!

@jason810496jason810496 left a comment

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Will the Lang SDK support stub syntax in native Dags in the future? (e.g. a native Java Dag that holds a Python or Go task)

Your understanding is correct! With the native Dag support in foreign Lang SDK, we can define the "primary" Dag with Stub Operator in foreign Lang SDK side and let the Python Dag implement the task body.

If not, please just ignore me.

From my perspective, I don't think we need to support this feature at all. It makes more sense to only support Python as the primary language for the mixed Lang Dag feature to keep the whole idea simple.

Airflow only supports Python DSL in the last decade! Additionally, the Stub Operator itself might be confusing for some of the user, so not to mention defining the Stub Operator in foreign Lang SDK (it will be mind blowing for the users I guess)

@Andrushika

Copy link
Copy Markdown
Contributor

Thanks for clarifying -- I have no further questions. These changes LGTM!

Sign up for freeto 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.

3 participants

@jason810496@uranusjr@Andrushika