Skip to content

feat(core): add per-mapper max_fan_out override for partition fan-out cap - #67184

Merged
Lee-W merged 4 commits into
apache:mainfrom
astronomer:partition-fanout-max-keys
Jun 11, 2026
Merged

Lee-W merged 4 commits into
apache:mainfrom
astronomer:partition-fanout-max-keys

Conversation

@Lee-W

@Lee-W Lee-W commented May 19, 2026 •

Copy link
Copy Markdown
Member

Why

a per-mapper cap so each PartitionMapper instance can override the global [scheduler] partition_fanout_max_keys (implemented in #66030)
Lives on the mapper rather than the Dag because one Dag can bind several mappers
with very different fan-out profiles.

closes: #65760

What

  • Add max_fan_out: int | None = None to PartitionMapper base (SDK + core). Validator rejects 0, negatives, non-int, and bool. None → global; positive int → override.
  • Thread the kwarg through every subclass that overrides __init__, and through both serialization paths (per-class .serialize() and the encoders.py singledispatch overrides). Field emitted only when non-None — pre-change payloads round-trip byte-identical.
  • assets/manager.py: read the cap per target Dag, swap a cap_source fragment into the audit-log extra (max_fan_out=N vs. existing [scheduler] partition_fanout_max_keys=N).

Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

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

@Lee-W Lee-W changed the title feat(AIP-76): window feat(core): add per-mapper max_fan_out override for partition fan-out cap May 19, 2026
@Lee-W
Lee-W force-pushed the partition-fanout-max-keys branch 14 times, most recently from d5d2ced to af057ae Compare May 28, 2026 10:11
@Lee-W
Lee-W force-pushed the partition-fanout-max-keys branch 3 times, most recently from 9f03f8d to efa8911 Compare May 29, 2026 14:13
@Lee-W
Lee-W force-pushed the partition-fanout-max-keys branch from c1521f6 to 81910a9 Compare June 8, 2026 13:03
@Lee-W
Lee-W force-pushed the partition-fanout-max-keys branch 4 times, most recently from aa011c3 to 03b76c8 Compare June 9, 2026 13:17
@Lee-W
Lee-W requested a review from uranusjr June 9, 2026 13:38
@Lee-W
Lee-W force-pushed the partition-fanout-max-keys branch 2 times, most recently from c15e65c to a26e224 Compare June 10, 2026 00:21
@Lee-W
Lee-W force-pushed the partition-fanout-max-keys branch 2 times, most recently from c634109 to cc440c8 Compare June 10, 2026 10:07
@Lee-W Lee-W removed the area:db-migrations PRs with DB migration label Jun 10, 2026
@Lee-W
Lee-W force-pushed the partition-fanout-max-keys branch 4 times, most recently from 1c8c418 to 9d28124 Compare June 10, 2026 15:30
Lee-W added 4 commits June 11, 2026 08:53
… fan-out cap

Add a `max_downstream_keys: int | None = None` parameter to both the SDK and
core `PartitionMapper` base classes, threaded through every subclass
constructor that defines its own `__init__`. The validator rejects 0,
negatives, floats, and strings.

Serialization is updated in two parallel paths:
- Per-class `serialize()` / `deserialize()` methods (custom-mapper path).
- `encoders.py` singledispatch overrides (built-in-mapper path).

Both paths write `max_downstream_keys` only when non-None, following the
existing convention of omitting default-valued fields from the serialized form.

In `manager.py`, the single-shot `max_downstream_keys` read is deleted;
the mapper object is retained after the `to_downstream` call so its
`max_downstream_keys` attribute is readable at the boundary check. The
effective cap is computed per target-Dag as either the mapper's own cap or the
global `[scheduler] partition_mapper_max_downstream_keys`. The `Log.extra`
string uses `max_downstream_keys=N` when the per-mapper cap trips, and keeps
the existing `[scheduler] partition_mapper_max_downstream_keys=N` wording when
the global trips.
The scheduler error log for a partition fan-out overflow now carries a
cap_source kwarg, so operators can tell whether the per-mapper
max_downstream_keys override or the global scheduler cap was the limit
that was hit.
…validator

Convert the SDK PartitionMapper base into an attrs class so the
max_downstream_keys bound is enforced through a field validator instead
of a hand-written __init__ check, matching the attrs convention used
across the rest of airflow.sdk.definitions. Behavior is unchanged.

Also add the SDK-side validator tests that previously only existed on
the core mapper hierarchy.
Make the whole SDK partition-mapper hierarchy use one mechanism so the
attrs base no longer needs a slots exception. RollupMapper, AllowedKeyMapper,
the temporal mappers, and FanOutMapper become attrs classes; ChainMapper and
ProductMapper keep their variadic __init__ via init=False. Public constructor
signatures and behavior are unchanged.
@Lee-W
Lee-W force-pushed the partition-fanout-max-keys branch from 9d28124 to 5f26df1 Compare June 11, 2026 00:53
@Lee-W
Lee-W merged commit b7247b1 into apache:main Jun 11, 2026
195 of 196 checks passed
@Lee-W
Lee-W deleted the partition-fanout-max-keys branch June 11, 2026 02:26
@github-project-automation github-project-automation Bot moved this from In Review to Done in AIP-76 Asset Partitioning Jun 11, 2026
imrichardwu pushed a commit to imrichardwu/airflow that referenced this pull request Jun 16, 2026
dingo4dev pushed a commit to dingo4dev/airflow that referenced this pull request Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

No open projects

Development

Successfully merging this pull request may close these issues.

Fan-out: explosion cap and error behavior

3 participants