Skip to content

Allow Variable.get to reuse the caller's database session - #71968

Draft
ferruzzi wants to merge 8 commits into
apache:mainfrom
aws-mwaa:ferruzzi/plumb-variable-session
Draft

Allow Variable.get to reuse the caller's database session#71968
ferruzzi wants to merge 8 commits into
apache:mainfrom
aws-mwaa:ferruzzi/plumb-variable-session

Conversation

@ferruzzi

@ferruzziferruzzi commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

MetastoreBackend.get_variable is decorated with @provide_session. Called without a session, it goes through create_session(), which returns the caller's own session for a scoped session and commits it on exit. So any code that reads a Variable while holding a transaction gets that transaction committed underneath it. That surfaces two ways:

  1. Outside the scheduler guard: the commit succeeds early and the caller's ORM objects are detached silently.
  2. Under the scheduler's prohibit_commit guard: it raises RuntimeError: UNEXPECTED COMMIT, which is then swallowed per-backend and surfaces as a missing Variable.

Variable.get, Variable.get_variable_from_secrets, and Variable.setdefault now take an optional keyword-only session, forwarded only to MetastoreBackend. Variable.update forwards its own.

Affected today:

  • Deadline Alerts using VariableInterval return "Variable not found" despite the Variable existing
  • Custom timetables reading a Variable in next_dagrun_info leave next_dagrun NULL, so the Dag is never eligible and never runs, with nothing logged

Both of the above are reached from _create_dagruns_for_dags, inside the guard. Dag sync via update_dags, Variable.update (fixed here), and Variable.setdefault (fixed here) hold a session without the guard, so they fail the silent way instead.

There are likely others; these are the ones I found.

Scope: This fixes the core Variable.update and Variable.setdefault outright and lets the remaining callers be fixed by passing session. airflow.sdk.Variable.get and Connection.get_connection_from_secrets share the same issue and are left as follow-ups, so callers going through those are still affected.

Related (that I know of)

closes: #71801


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

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


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

`MetastoreBackend.get_variable` is decorated with `@provide_session`. Called
without a session it goes through `create_session()`, which for a scoped session
returns *the caller's own session* and commits it on exit. So any code that reads
a Variable while holding a transaction gets that transaction committed underneath
it — detaching its objects, or raising `UNEXPECTED COMMIT` under the scheduler's
`prohibit_commit` guard, where the error is then swallowed per-backend and
surfaces as a missing Variable.
`Variable.get` and `Variable.get_variable_from_secrets` now take an optional
keyword-only `session`, forwarded only to `MetastoreBackend`. `Variable.update`
forwards its own.
Affected today, all reached from `_create_dagruns_for_dags` inside the guard:
* Deadline Alerts using `VariableInterval`
* Custom timetables reading a Variable in `next_dagrun_info` — `next_dagrun` is
left NULL, so the Dag is never eligible and never runs, with nothing logged
* Dag sync via `update_dags`; `Variable.update`; `Variable.setdefault`
Scope: this fixes the core read path only. `airflow.sdk.Variable.get` and
`Connection.get_connection_from_secrets` share the defect and are unchanged, so
callers going through those are still affected. apache#68917 can drop its duplicated
backend walk once this lands.
closes: apache#71801
@ferruzzi
ferruzzi marked this pull request as ready for review August 21, 2026 23:27
Comment threadairflow-core/src/airflow/models/variable.py Outdated
Comment threadairflow-core/newsfragments/71968.bugfix.rst Outdated
Comment threadairflow-core/src/airflow/models/variable.py Outdated
@ferruzzi
ferruzzi requested a review from potiuk as a code ownerAugust 25, 2026 00:22
@vincbeckvincbeck added the backport-to-v3-3-test Backport to v3-3-test label Aug 25, 2026
@ferruzziferruzzi added this to the Airflow 3.3.2 milestone Aug 25, 2026

@ferruzziferruzzi left a comment

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a blocking comment to prevent accidental merge. PR #71802 will present a merge conflict and it will be easier to resolve if that one merges before this one. Also moving this to draft just in case, but please leave that comment unresolved as an enforced "do not merge" blocker.

Comment on lines +149 to +150
:param session: Existing session to reuse for the metadata database read and write.
Callers holding an open transaction must pass it.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On hold until #71802 merges. That PR adds SerializedVariableInterval.resolve(), which reads a Variable while the scheduler is already holding a session, so it becomes the first real caller for
this parameter. Once it lands I'll add session to resolve() and pass it through to Variable.get() here, rather than merging a parameter with no consumers.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow Variable.get_variable_from_secrets to reuse a caller's session

3 participants

@ferruzzi@o-nikolas@vincbeck