fixed sort order for mapped task instances#67551
Conversation
pierrejeambrun
left a comment
There was a problem hiding this comment.
Do you have screenshot of before/after to highlight the behavior.
There is also the get_task_instances endpoint that specifies the rendered_map_indexes in the order param, that should probably be also updated.
I think this fixes the part where rendered_map_index is None, but that's actually almost never the case. Unless the dynamic tasks mapping isn't expended yet, rendred_map_index will fallback to the map_index.
|
Tested using the following DAG: from datetime import datetime
from airflow.decorators import dag, task
@dag(
dag_id="dynamic_mapped_dag",
start_date=datetime(2026, 1, 1),
schedule=None,
catchup=False,
tags=["dynamic", "mapped"],
)
def dynamic_mapped_dag():
@task
def generate_indexes() -> list[int]:
return list(range(126))
@task
def process(index: int) -> int:
print(f"Processing map_index={index}")
return index
@task(map_index_template="{{ user }}")
def process_labeled(user: str) -> str:
print(f"Processing user={user}")
return user
process.expand(index=generate_indexes())
process_labeled.expand(user=["zebra", "apple", "mango", "cherry", "banana"])
dynamic_mapped_dag()Task:
|
pierrejeambrun
left a comment
There was a problem hiding this comment.
LGTM thanks.
CI isn't happy some tests need adjustment.
One nit / question and good to go I believe.
|
Pagination isn't working anymore: Screen.Recording.2026-05-27.at.13.46.50.mov |
…iption When `rendered_map_index` (and other keys like `run_after`, `logical_date`, `data_interval_start`, `data_interval_end`) are present in both `allowed_attrs` and `to_replace`, `dynamic_depends` was appending them twice to `all_attrs`, causing the generated `order_by` parameter description to list those attributes twice. This caused the `generate-openapi-spec` static check to fail. Fix: deduplicate `to_replace_attrs` by excluding keys already in `allowed_attrs` before building `all_attrs`. Update the committed OpenAPI spec to match.
|
@manipatnam A few things need addressing before review — see our Pull Request quality criteria.
No rush. Note: This comment was drafted by an AI-assisted triage tool and may contain mistakes. Once you have addressed the points above, an Apache Airflow maintainer — a real person — will take the next look at your PR. We use this two-stage triage process so that our maintainers' limited time is spent where it matters most: the conversation with you. |
|
CI need fixing |















order_by=rendered_map_indexon thelistMappedandlistTaskInstancesendpoints had a bug:CAST(map_index AS String)fallback produces string comparison:"10"sorts before"2","20"before"3", etc. A Dag with 12 mapped tasks returned them as0, 1, 10, 11, 2, 3 …instead of0, 1, 2, 3 … 10, 11.closes: #67451
Root cause
SortParamresolvedrendered_map_indexto a single column forORDER BY. With a nullable primary column and a string-cast fallback, there was no stable integer secondary key, so UUID ordering determined page membership for tasks withoutmap_index_template.Fix
Extend
SortParam.to_replaceto acceptlist[Column]as a compound sort: a single user-facing sort key expands into multipleORDER BYcolumns. BothlistMappedandlistTaskInstancesnow maprendered_map_indexto[TI._rendered_map_index, TI.map_index],producing:map_index_template(common case)_rendered_map_indexNULL → tie on key 1 → sorted by integermap_index→0, 1, 2, 10, 11 …map_index_templatemap_indexfor tiesmap_index)Changes
airflow/api_fastapi/common/parameters.pySortParam.__init__type annotation extended:dict[str, str | Column | list[Column]] | NoneSortParam._resolve()— when ato_replacevalue is alist, each column is expanded into its own sort entry using the column's ORM.keyasattr_name, sorow_value()resolves it viagetattrwithout any additional lookup.SortParam.row_value()— guard updated to skip list-form values (they are already expanded in_resolve()).airflow/api_fastapi/core_api/routes/public/task_instances.pylistMappedandlistTaskInstancesSortParamboth gain"rendered_map_index": [TI._rendered_map_index, TI.map_index]in theirto_replacedicts.Tests
rendered_map_index/-rendered_map_indexcases in the existingtest_mapped_instances_orderparametrize to expect numeric order (list(range(100))/list(range(109, 9, -1))) instead of the previous lexicographic expectations (sorted(range(110), key=str)).test_rendered_map_index_order_with_template: verifies that when all TIs have a custom_rendered_map_indexlabel the sort is alphabetical by label.test_rendered_map_index_order_retried_tis_not_displaced: simulates retries by assigning newer UUIDs to some TIs and verifies all TIs still appear on the first page inmap_indexorder.Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (claude-sonnet-4-6) following the guidelines