Skip to content

Fix scheduler DBDagBag unbounded cache - #71704

Merged
jason810496 merged 1 commit into
apache:mainfrom
jason810496:fix/scheduler/dbdagbag-unbounded-cache
Aug 19, 2026
Merged

Fix scheduler DBDagBag unbounded cache#71704
jason810496 merged 1 commit into
apache:mainfrom
jason810496:fix/scheduler/dbdagbag-unbounded-cache

Conversation

@jason810496

@jason810496 jason810496 commented Aug 17, 2026

Copy link
Copy Markdown
Member

Why

The scheduler kept every Dag version it deserialized in a mapping that never evicted, so a long-running scheduler grew with the number of versions it had ever seen until it was restarted or OOM killed. Deployments that redeploy Dags frequently accumulate versions fastest and hit this soonest.

How

One line. DBDagBag already builds a bounded LRU cache when given a cache_size; the scheduler simply never passed one.

-        self.scheduler_dag_bag = DBDagBag(load_op_links=False)
+        self.scheduler_dag_bag = DBDagBag(load_op_links=False, cache_size=SCHEDULER_DAG_CACHE_SIZE)

No changes to DBDagBag, to the API server, or to configuration — deliberately, so this cherry-picks cleanly.

Why a size cap rather than a TTL

A least-recently-used cap is the only thing that bounds the cache outright. An idle timeout would not: _get_dag re-checks an entry on each lookup, and cachetools re-arms expiry on assignment, so a TTL reclaims a version only once its runs finish and it stops being requested. That leaves memory a function of the concurrently active set rather than a fixed ceiling.

Where the working set exceeds the cap, the evicted version is re-fetched and deserialized on the next loop. Correctness is unaffected — a cache miss is a re-read, never a wrong Dag.

Known limitation

Enabling the cache also enables DBDagBag's metrics, which are currently hard-coded to api_server.dag_bag.*. Those counters therefore now include scheduler traffic. Giving each component its own namespace requires a DBDagBag API change, deferred to #71815. Making the cap configurable is #71816, and #71814 fixes [api] dag_cache_size = 0 silently ignoring [api] dag_cache_ttl.


Was generative AI tooling used to co-author this PR?
  • Yes — Claude Code (Opus 5)

Generated-by: Claude Code (Opus 5) following the guidelines

@boring-cyborg boring-cyborg Bot added area:API Airflow's REST/HTTP API area:ConfigTemplates area:dev-tools area:Scheduler including HA (high availability) scheduler backport-to-v3-3-test Backport to v3-3-test kind:documentation labels Aug 17, 2026
@jason810496 jason810496 self-assigned this Aug 17, 2026
@jason810496
jason810496 force-pushed the fix/scheduler/dbdagbag-unbounded-cache branch 2 times, most recently from e3a4ee1 to 09561d4 Compare August 17, 2026 12:52
Comment thread airflow-core/src/airflow/config_templates/config.yml Outdated
@jason810496
jason810496 force-pushed the fix/scheduler/dbdagbag-unbounded-cache branch from 09561d4 to 522a76d Compare August 17, 2026 13:35
@jason810496 jason810496 changed the title Fix Scheduler DBDagBag Unbounded Cache Fix scheduler DBDagBag unbounded cache Aug 17, 2026
@jason810496
jason810496 marked this pull request as ready for review August 17, 2026 13:37
@jason810496 jason810496 added this to the Airflow 3.3.2 milestone Aug 17, 2026
@jason810496
jason810496 force-pushed the fix/scheduler/dbdagbag-unbounded-cache branch from 522a76d to 95c235d Compare August 18, 2026 01:36
@jason810496
jason810496 requested a review from ashb August 18, 2026 16:11
@ashb

ashb commented Aug 18, 2026

Copy link
Copy Markdown
Member

1024 dag (versions) is probably too aggressive a default?

Do you mean too large or too low by default? Or what threshold do you recommend to set?

I'm thinking its too large. 512 or 256 might be a safer default? (I just worry about how much memory 1024 dags in memory at once could take up

@uranusjr

Copy link
Copy Markdown
Member

Let’s say a dag needs 500 bytes to store a task, and each dag has 100 tasks. That’s 50k for a dag. 256→13m, 512→25m, 1024→50m. It doesn’t sound too bad to me. Let’s do 512?

@uranusjr

Copy link
Copy Markdown
Member

I think we should roll back all API changes in this PR and simply change the scheduler. The scheduler cache also should not rely on any configurations. (It currently still does dag_cache_conf, just to all non-existent configs so only use defaults.) Everything else should be done in later PRs. This is important so the PR can be cherry-picked cleanly.

@jason810496
jason810496 marked this pull request as draft August 19, 2026 05:06
@jason810496

Copy link
Copy Markdown
Member Author

I think we should roll back all API changes in this PR and simply change the scheduler. The scheduler cache also should not rely on any configurations. (It currently still does dag_cache_conf, just to all non-existent configs so only use defaults.) Everything else should be done in later PRs. This is important so the PR can be cherry-picked cleanly.

Sure, then I will just make this one a minimal fix (just hardcoded the cache size as 512 for scheduler only) if we don't want to introduce any config at all. Please noted that this means user will need to wait for 3.4.0 to set the cache size via config.

@jason810496
jason810496 force-pushed the fix/scheduler/dbdagbag-unbounded-cache branch 2 times, most recently from 4b308b2 to f2d6575 Compare August 19, 2026 05:25
jason810496 added a commit to jason810496/airflow that referenced this pull request Aug 19, 2026
The scheduler cache bound it originally accompanied now ships separately in
apache#71704; what remains here is the configuration, metric namespacing, and the
`[api]` TTL fix, so the entry belongs to this PR's number.
The scheduler kept every Dag version it deserialized in a mapping that never
evicted, so a long-running scheduler grew with the number of versions it had
ever seen until it was restarted or OOM killed. Deployments that redeploy Dags
frequently accumulate versions fastest and hit this soonest.

A least-recently-used cap is the only thing that bounds this outright. An idle
timeout would not: the scheduler re-checks an entry on each lookup, which
re-arms its expiry, so a timeout reclaims a version only once its runs finish
and it stops being requested, leaving memory a function of the concurrently
active set rather than a fixed ceiling.

Deliberately not configurable here, so the fix stays small enough to
cherry-pick. Cache activity currently reports under the existing
api_server.dag_bag.* metrics; a scheduler-specific namespace, along with
configuration, follows separately.

closes: apache#69001
@jason810496
jason810496 force-pushed the fix/scheduler/dbdagbag-unbounded-cache branch from f2d6575 to addab6b Compare August 19, 2026 05:54
@jason810496
jason810496 marked this pull request as ready for review August 19, 2026 05:58
@vatsrahul1001 vatsrahul1001 added the backport-to-v3-3-test Backport to v3-3-test label Aug 19, 2026
@jason810496
jason810496 merged commit 29dd99d into apache:main Aug 19, 2026
131 of 136 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Backport successfully created: v3-3-test

Note: As of Merging PRs targeted for Airflow 3.X
the committer who merges the PR is responsible for backporting the PRs that are bug fixes (generally speaking) to the maintenance branches.

In matter of doubt please ask in #release-management Slack channel.

Status Branch Result
v3-3-test PR Link

jason810496 added a commit that referenced this pull request Aug 19, 2026
…1821)

The scheduler kept every Dag version it deserialized in a mapping that never
evicted, so a long-running scheduler grew with the number of versions it had
ever seen until it was restarted or OOM killed. Deployments that redeploy Dags
frequently accumulate versions fastest and hit this soonest.

A least-recently-used cap is the only thing that bounds this outright. An idle
timeout would not: the scheduler re-checks an entry on each lookup, which
re-arms its expiry, so a timeout reclaims a version only once its runs finish
and it stops being requested, leaving memory a function of the concurrently
active set rather than a fixed ceiling.

Deliberately not configurable here, so the fix stays small enough to
cherry-pick. Cache activity currently reports under the existing
api_server.dag_bag.* metrics; a scheduler-specific namespace, along with
configuration, follows separately.
(cherry picked from commit 29dd99d)


closes: #69001

Co-authored-by: Jason(Zhe-You) Liu <68415893+jason810496@users.noreply.github.com>
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.

Scheduler DBDagBag cache is never evicted and grows unbounded

6 participants