Skip to content

Reduce scheduler memory for asset-triggered Dag runs - #69849

Open
viiccwen wants to merge 1 commit into
apache:mainfrom
viiccwen:optimize-asset-event-association-memory
Open

Reduce scheduler memory for asset-triggered Dag runs#69849
viiccwen wants to merge 1 commit into
apache:mainfrom
viiccwen:optimize-asset-event-association-memory

Conversation

@viiccwen

@viiccwen viiccwen commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Description

closes #69848

Asset-triggered Dag run creation currently materializes every matching AssetEvent ORM object, including its JSON metadata, before writing the Dag run association rows. Large event windows can therefore cause scheduler memory spikes far beyond the raw payload size.

This change writes the association rows with a server-side INSERT ... SELECT while preserving the existing event predicates, transaction boundary, exact event membership, and relationship behavior.

Scheduler-side AssetEvent ORM and JSON payload materialization drops from O(events) to approximately O(1). The database still performs O(events) work to select event IDs and persist one association row per event; this change moves that set operation out of Python rather than eliminating it.

The partitioned-asset path uses the same set-based association helper. No schema or configuration change is needed.

Benchmark

The benchmark invokes the real scheduler path on SQLite, PostgreSQL, and MySQL with a 512-byte JSON
payload per event. Setup is outside the measured interval.

Database Events Duration (before/after) Speedup Python peak (before/after) Peak reduction
SQLite 1,000 0.537 / 0.255s 2.11× 6.23 / 0.16 MB 97.2%
SQLite 10,000 1.785 / 0.024s 74.38× 54.24 / 0.11 MB 99.8%
SQLite 50,000 12.545 / 0.071s 176.69× 274.21 / 0.13 MB 99.95%
PostgreSQL 1,000 0.339 / 0.237s 1.43× 7.39 / 1.84 MB 75.1%
PostgreSQL 10,000 2.510 / 0.096s 26.15× 62.34 / 0.12 MB 99.8%
PostgreSQL 50,000 10.046 / 0.688s 14.60× 289.72 / 0.14 MB 99.95%
MySQL 1,000 0.161 / 0.032s 5.00× 5.80 / 0.16 MB 97.2%
MySQL 10,000 4.478 / 0.185s 24.21× 54.54 / 0.11 MB 99.8%
MySQL 50,000 21.502 / 1.977s 10.88× 272.63 / 0.13 MB 99.95%

The 1,000-event result includes first-call and tracing warm-up overhead.

Notes

  • consumed_asset_event_count is designed for logging, can discuss leave it or not.

Was generative AI tooling used to co-author this PR?
  • Yes - Codex (GPT 5.6 Sol)

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

@viiccwen
viiccwen requested review from XD-DENG and ashb as code owners July 14, 2026 05:29
@boring-cyborg boring-cyborg Bot added the area:Scheduler including HA (high availability) scheduler label Jul 14, 2026
@viiccwen

Copy link
Copy Markdown
Contributor Author

cc @Lee-W, @jason810496. ✨🙌

@Lee-W
Lee-W self-requested a review July 14, 2026 06:09

@Lee-W Lee-W 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! I remember we did something similar elsewhere. the overall idea looks good to me

Comment thread airflow-core/src/airflow/jobs/scheduler_job_runner.py Outdated
Comment thread airflow-core/src/airflow/jobs/scheduler_job_runner.py Outdated
@viiccwen
viiccwen force-pushed the optimize-asset-event-association-memory branch from c250d56 to bb68de6 Compare July 14, 2026 14:50
@viiccwen

Copy link
Copy Markdown
Contributor Author

cc @Lee-W. 🫡

Lee-W
Lee-W previously approved these changes Jul 16, 2026
@Lee-W
Lee-W requested review from jason810496 and uranusjr July 16, 2026 10:38
@eladkal eladkal added this to the Airflow 3.3.1 milestone Jul 16, 2026
@eladkal eladkal added type:bug-fix Changelog: Bug Fixes backport-to-v3-3-test Backport to v3-3-test labels Jul 16, 2026
Large asset event windows can exhaust scheduler memory because every event, including JSON metadata, is materialized as an ORM object before its Dag run association is persisted. Concurrent arrivals must also remain isolated from the event window used to derive each run's timestamp.

Signed-off-by: viiccwen <vicwen@apache.org>
@viiccwen
viiccwen force-pushed the optimize-asset-event-association-memory branch from bb68de6 to e042524 Compare August 8, 2026 07:39
@viiccwen

viiccwen commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

Hello @Lee-W, since upstream had been heavily modified, need review again. 🙏

@uranusjr
uranusjr dismissed Lee-W’s stale review August 9, 2026 17:53

Re-review required due to heavy rebase

Comment on lines +2769 to +2770
selected_asset_events.c.timestamp <= triggered_date,
selected_asset_events.c.event_id <= max_selected_event_id,

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.

This looks like dead weight unless the reader understands the CTE is re-evaluated fresh in this second, independent query and could pick up events inserted after the aggregate read. Add a comment explaining this is a snapshot bound against a race, not a no-op.

Comment on lines +2778 to +2785
consumed_asset_event_count = (
session.scalar(
select(func.count())
.select_from(association_table)
.where(association_table.c.dag_run_id == dag_run.id)
)
or 0
)

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.

We can probably use rowcount instead? If we must use a separate query, it’d be a good idea to at least add a guard on log level (with isEnabledFor)

select(literal(dag_run.id), selected_event_ids.c.event_id),
)
)
session.expire(dag_run, ["consumed_asset_events"])

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.

Worth a comment explaining why manual expiration is needed.

@uranusjr

uranusjr commented Aug 9, 2026

Copy link
Copy Markdown
Member

I think this is close to mergeable with some nits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Scheduler including HA (high availability) scheduler backport-to-v3-3-test Backport to v3-3-test type:bug-fix Changelog: Bug Fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Asset-triggered Dag runs cause scheduler memory spikes

5 participants