Skip to content

TS SDK: resolve upstream XComs for bound TaskFlow arguments - #73190

Merged
jason810496 merged 1 commit into
apache:mainfrom
jason810496:feature/ts-sdk/taskflow-xcom-args
Sep 18, 2026
Merged

jason810496 merged 1 commit into
apache:mainfrom
jason810496:feature/ts-sdk/taskflow-xcom-args

Conversation

@jason810496

@jason810496 jason810496 commented Sep 15, 2026 •

Copy link
Copy Markdown
Member

TS SDK: resolve upstream XComs for bound TaskFlow arguments

Why

summarize(extract()) means "hand the handler what extract returned", but only literals could bind,
so such an argument failed the task and told the author to pull the XCom by hand.

How

  • Airflow names the upstream task in the binding spec, so the runtime pulls those return_value XComs itself, all of them concurrently:
    a task called with four upstream outputs waits for one round-trip, not four.
  • The whole spec is still validated before anything is pulled, so a binding this SDK cannot honour costs no round-trip,
    and leaves no half-resolved call behind.
  • Arguments resolve before the handler runs, the one stretch of a task's life with nothing else listening for termination,
    so the abort signal cuts the pulls short rather than leaving a killed task to sit out the force-exit grace period.
  • An upstream that pushed no output fails the task, naming both the argument and the task it came from.
    Telling that apart from an upstream that pushed null needs more than getXCom, which answers null for both,
    so the coordinator's own client keeps the found flag the supervisor already sends. Handlers stay typed against TaskClient and never see it.
  • A Python int beyond the range a JavaScript number holds exactly is refused rather than bound.
    Airflow stamps format: "int64" on the argument, and the value arrives with its low digits already lost, so nothing downstream could notice.

Note

ADR-0001 decision 6 is unchanged: being upstream is not being passed.
A >> dependency still declares order only, and a value the call did not pass is still read explicitly.


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

A Python Dag calling a TypeScript task TaskFlow-style, as in
`summarize(extract())`, means "hand the handler what extract returned". But the
runtime could only bind literals: an argument taking an upstream task's output
failed the task and told the author to pull the XCom by hand, so the call site
stopped being the contract exactly where it mattered most.

Airflow names the upstream task in the binding spec, so the runtime pulls those
outputs itself, all of them at once, since a task called with four upstream
outputs should wait for one round-trip rather than four. The whole spec is
still checked before anything is pulled, so a binding this SDK cannot honour
costs no round-trip.

They resolve before the handler is called, which is also the one stretch of a
task's life with nothing else listening for termination, so the task's abort
signal now cuts them short instead of leaving a killed task to sit out the
force-exit grace period.

An upstream that pushed no output fails the task, naming both the argument and
the task it came from: a task that returns nothing pushes no XCom, and an
unbound argument corrupts the handler's output rather than stopping it. Telling
that apart from an upstream that pushed null takes more than the task client's
JS-friendly `getXCom`, which answers null for both, so the coordinator's own
client keeps the found flag the supervisor already sends. Handlers stay typed
against `TaskClient` and never see it.

A Python `int` beyond the range a JavaScript number holds exactly is refused
for the same reason: Airflow stamps `format: "int64"` on the argument, and the
value arrives with its low digits already lost, so binding it would hand the
handler a different number from the one the Dag produced.

What does not change is ADR-0001 decision 6: an upstream's return value is not
a bound argument unless the call passes it.
@jason810496
jason810496 force-pushed the feature/ts-sdk/taskflow-xcom-args branch from 3f43c95 to 1e94738 Compare September 18, 2026 13:52

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

Thanks

@jason810496
jason810496 merged commit b295dde into apache:main Sep 18, 2026
91 checks passed
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.

2 participants