Skip to content

Add Execution API endpoint for callback terminal state - #75253

Merged
ferruzzi merged 6 commits into
apache:mainfrom
aws-mwaa:callback-state-endpoint
Nov 10, 2026
Merged

ferruzzi merged 6 commits into
apache:mainfrom
aws-mwaa:callback-state-endpoint

Conversation

@ferruzzi

@ferruzzi ferruzzi commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Callback state was written only by the scheduler, reading each executor's in-process event buffer. Executors whose workers report back over HTTP never reach that channel, so their callbacks sat in QUEUED forever.

The executor-event path stays as a fallback, now narrowed to rows still in flight so a late event cannot overwrite an outcome the supervisor already reported, or the output captured with it.

Replaces #66141, whose /run half landed separately in #71192. Most of this is @wjddn279's code from that PR ported on top of the current main, co-author credit should carry over.


Was generative AI tooling used to co-author this PR?
  • [ x ] Yes (please specify the tool below)
    Inheriting the disclaimer from the parent PR: claude code (opus 4.7) to make test codes and ci green

  • Read the Pull Request Guidelines for more information. Note: commit author/co-author name and email in commits become permanently public when merged.
  • For fundamental code changes, an Airflow Improvement Proposal (AIP) is needed.
  • When adding dependency, check compliance with the ASF 3rd Party License Policy.
  • For significant user-facing changes create newsfragment: {pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.

@fat-catTW fat-catTW left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the scheduler fallback could race with the new state endpoint here.

The scheduler reads the callback without a lock, checks that it is still QUEUED/RUNNING, and later writes the executor event's terminal state. In between those operations, the callback supervisor can successfully report SUCCESS (including its output) through PATCH /callbacks/{callback_id}/state.

For example, the callback subprocess can succeed and report SUCCESS, while the outer supervisor subsequently exits abnormally and the executor emits a late FAILED event. The scheduler could then overwrite the supervisor's already-recorded result, despite the intended first-writer-wins behaviour.

Maybe we could lock the callback row before rechecking its state, or use a conditional update that only succeeds while the persisted state is still QUEUED or RUNNING and add a regression test for this interleaving?

@fat-catTW fat-catTW left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm
Thanks for the PR :D

@seanghaeli seanghaeli left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also a conflict to deal with, but otherwise looks ready!

@ramitkataria ramitkataria left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The conditional UPDATE looks like a nice fix for the race. A few smaller things my agent found on top of the inline comments:

- +1 to the suggestion on `routes/callbacks.py` about returning 204 when the row is already in the requested state, so retries don't log a traceback.
- Which executors is this mainly for? Edge seems to already pass callback events back to the scheduler since #74784, so maybe worth naming the ones that don't in the description. For those, a failed `/run` or an OOM-killed supervisor would still leave the row stuck, so the comment at `callback_supervisor.py:469` might want a tweak, and maybe a follow-up issue for a timeout-based cleanup of stuck `QUEUED`/`RUNNING` callbacks?
- `jwt_token_authentication.rst` still only lists `/run` for callbacks, so maybe worth adding `/state` there too.
- After rebasing onto #75689, it might be worth double-checking the 404 case in `test_state_validates_token_scope_and_sub`, since it depends on the order the auth dependencies resolve in.

@ferruzzi
ferruzzi force-pushed the callback-state-endpoint branch from 8486c4e to 726dc55 Compare November 3, 2026 00:17

@o-nikolas o-nikolas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agreed about a separate PR for the callouts from @ramitkataria

ferruzzi and others added 6 commits November 9, 2026 20:17
Callback state was written only by the scheduler, reading each executor's in-process event buffer. Executors whose workers report back over HTTP never reach that channel, so their callbacks sat in QUEUED forever.

The executor-event path stays as a fallback, now narrowed to rows still in flight so a late event cannot overwrite an outcome the supervisor already reported, or the output captured with it.

Replaces apache#66141, whose /run half landed separately in apache#71192.

Co-authored-by: wjddn279 <[email protected]>
@ferruzzi
ferruzzi force-pushed the callback-state-endpoint branch from 726dc55 to 917ad67 Compare November 10, 2026 03:29
@ferruzzi
ferruzzi merged commit 27e807b into apache:main Nov 10, 2026
103 checks passed
@ferruzzi
ferruzzi deleted the callback-state-endpoint branch November 10, 2026 21:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants