AIP-103: Add Execution API endpoints for task and asset states#66073
Merged
amoghrajesh merged 8 commits intoapache:mainfrom May 4, 2026
Merged
AIP-103: Add Execution API endpoints for task and asset states#66073amoghrajesh merged 8 commits intoapache:mainfrom
amoghrajesh merged 8 commits intoapache:mainfrom
Conversation
jscheffl
reviewed
Apr 29, 2026
9912b2d to
c6a1a3b
Compare
c6a1a3b to
701ca4f
Compare
1 task
kaxil
reviewed
Apr 30, 2026
jscheffl
approved these changes
May 1, 2026
kaxil
reviewed
May 2, 2026
Contributor
Author
|
Rerunning with full tests |
Contributor
Author
Contributor
Backport failed to create: v3-2-test. View the failure log Run detailsNote: As of Merging PRs targeted for Airflow 3.X In matter of doubt please ask in #release-management Slack channel.
You can attempt to backport this manually by running: cherry_picker ffb1b8a v3-2-testThis should apply the commit to the v3-2-test branch and leave the commit in conflict state marking After you have resolved the conflicts, you can continue the backport process by running: cherry_picker --continueIf you don't have cherry-picker installed, see the installation guide. |
Contributor
Author
|
No need to rebase |
This was referenced May 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Was generative AI tooling used to co-author this PR?
Only the last commit is relevant, this has been built on top of #65759
closes: #66069
This PR is part of AIP-103 (Task State Management) and adds the execution API endpoints for task and asset state.
Summary
/execution/state/:GET/PUT/DELETE /state/ti/{task_instance_id}/{key}andDELETE /state/ti/{task_instance_id}to clear all keys for a taskGET/PUT/DELETE /state/asset/{name}/{key}andDELETE /state/asset/{name}to clear all keys for an asset[state_store] backend(defaults toMetastoreStateBackendfrom PR 1). Custom worker-side backendsbypass the API entirely (although I think I should hardcode
MetastoreStateBackendin API server since we do not want statebackend credentials there?)
Security(require_auth, scopes=["ti:self"])on the router — a task can only access its own state.
get_state_backend()inairflow.state.A few design choices worth flagging
Two shapes:
A: API resolves backend, ie: worker → API → could be DB, S3, Redis, or even metastore.
B: API = always DB, ie: worker → backend and API → metastore only. Custom backends live worker-side only and bypass the API — anything stored on a custom state backend goes via the worker itself; if not configured, it falls through to metastore via the API.
Why Shape B?
But I would love to hear thoughts on A. If not, I can hardcode
MetastoreStateBackendin the API endpoints.Asset state routes use
name(not integerasset_id) in the URL. Asset names are unique, directly available on the task'sAssetobject at runtime (no extra lookup), and consistent with how/assets/by-namealready works. The integerasset_idis an internal DB detail that shouldn't leak into the API surface.Why we don't pass the route's
sessioninto the backend. First attempt threadedsession=sessionfromSessionDepintobackend.set(...). mypy rightly complained —BaseStateBackend.setdoesn't declare asessionkwarg, onlyMetastoreStateBackend.setdoes (via@provide_session). I went back and forth on adding*, session: Any = Noneto the abstract methods, but it leaks a SQLAlchemy concept into an interface that S3/Redis/GCS backends have no use for.So: backend manages its own session via
@provide_session→create_session(). Routes keepSessionDepfor non-backend lookups (TaskInstance / AssetModel existence) — those are reads, no commit needed. Cost is one extra session per state op, negligible. Worth it to keep the abstraction clean.No Cadwyn migration. These are net-new endpoints. Old clients that don't call them are unaffected.
Mapped task semantics. PUT, GET, single-key DELETE, and default DELETE-all all stay scoped to one mapped instance —
task_instance_idresolves to a unique(dag_id, run_id, task_id, map_index). Fleet-wide wipe (across everymap_index) is opt-in via?all_map_indices=trueon DELETE-all. Destructive bulk is never the default; SDK passes the flag only when the caller asks for it.What's deferred / todo so far
/assetsand/asset-eventstoday — the proper fix is a unified check across all asset routes, which I will probably try before merge here. TODO inasset_state.py.Testing Manually
Setup
Example:
Testing
Regular Tasks
Validation:
Validation:

All gone:

Mapped Tasks
DELETE /state/ti/{ti_id}wipes state across everymap_indexof the task, not just its own. The reasoning: clear-all is a "task is done with its state" operation, not a per-instance reset. Per-instance reset is already covered by DELETE. Showcasing that below.Using this DAG:
Ran it and this is TI:

Pushed in task_state for map_index: 0,1,4
00000000-0000-0000-0000-000000000001(Negative case)(It just deleted it for that task_state with map_index as 4)
all_map_indicesto see if it deletes allAll have been deleted
Assets being tested
5a. Put asset state:
5b. Get asset state:
5c. Delete asset state
5d. Delete all asset state
For that adding multiple keys, for same asset
Running delete all request
All gone:
{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.