Skip to content

Stop the secrets backend lookup from importing the task runner outside tasks - #74641

Merged
kaxil merged 1 commit into
apache:mainfrom
astronomer:secrets-lookup-without-task-runner-import
Oct 14, 2026
Merged

kaxil merged 1 commit into
apache:mainfrom
astronomer:secrets-lookup-without-task-runner-import

Conversation

@kaxil

@kaxil kaxil commented Oct 13, 2026

Copy link
Copy Markdown
Member

ensure_secrets_backend_loaded() checks whether it is running inside a task by importing task_runner and reading SUPERVISOR_COMMS. Outside a task, that import loads the task runtime just to learn the answer is no. It now reads the module from sys.modules, as mask_secret does since #74496 and as Connection and Variable in airflow-core already do. Anything that sets SUPERVISOR_COMMS has imported task_runner first, so the answer is the same.

That import was also what loaded the task runner in the supervisor before it forks the task process, so every forked task inherited it. Callback processes inherited it too when remote logging has a connection, since that lookup goes through the same function. This keeps it on purpose: ActivitySubprocess.start and CallbackSubprocess.start now import the task runner before a bare fork. Without that, each task process would import it after the fork, which is 240 modules and about 590 ms per task in breeze (median of 7 runs; breeze runs without bytecode caching, so an installed Airflow is faster). A spawned interpreter (macOS, or execute_tasks_new_python_interpreter) imports its own copy anyway, so the task path skips the import there.

If the import fails in the supervisor, for example with sentry_on set but sentry_sdk missing, the error is ignored there. The child imports it again and reports the error in the task log, as it did before.

The side-effect import also made provider tests that patch builtins.open for the whole process depend on test order. When one of them was the first to import the task runner, the metrics registry read its YAML through the mock. Run alone on main, 7 of them fail: the five test_create_keytab_path_from_base64_keytab_* tests for the Spark submit hook, TestKubernetesPodOperatorAsync::test_skip_deferral_on_terminated_pod, and the OpenAI hook's test_upload_file. They pass alone with this change.

…e tasks

ensure_secrets_backend_loaded() imported task_runner to check whether
SUPERVISOR_COMMS was set. Outside a task, that loaded the task runtime
just to learn the answer was no. Read the module from sys.modules
instead, as mask_secret already does.

That import also loaded the task runner in the supervisor before it
forked the task process, and before callback processes when remote
logging has a connection, so those children inherited it. Import it
explicitly before a bare fork of a task or callback process instead, so
each child does not import it again. If the import fails there, the
child imports it again and reports the error in its own log, as before.
@kaxil
kaxil merged commit f46a370 into apache:main Oct 14, 2026
187 of 188 checks passed
@kaxil
kaxil deleted the secrets-lookup-without-task-runner-import branch October 14, 2026 03:02
@vatsrahul1001 vatsrahul1001 added this to the Airflow 3.4.0 milestone Oct 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Backport successfully created: v3-4-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-4-test PR Link

vatsrahul1001 pushed a commit that referenced this pull request Oct 18, 2026
…unner outside tasks (#74641) (#74980)

ensure_secrets_backend_loaded() imported task_runner to check whether
SUPERVISOR_COMMS was set. Outside a task, that loaded the task runtime
just to learn the answer was no. Read the module from sys.modules
instead, as mask_secret already does.

That import also loaded the task runner in the supervisor before it
forked the task process, and before callback processes when remote
logging has a connection, so those children inherited it. Import it
explicitly before a bare fork of a task or callback process instead, so
each child does not import it again. If the import fails there, the
child imports it again and reports the error in its own log, as before.
(cherry picked from commit f46a370)

Co-authored-by: Kaxil Naik <kaxilnaik@gmail.com>
vatsrahul1001 pushed a commit that referenced this pull request Oct 20, 2026
…unner outside tasks (#74641) (#74980)

ensure_secrets_backend_loaded() imported task_runner to check whether
SUPERVISOR_COMMS was set. Outside a task, that loaded the task runtime
just to learn the answer was no. Read the module from sys.modules
instead, as mask_secret already does.

That import also loaded the task runner in the supervisor before it
forked the task process, and before callback processes when remote
logging has a connection, so those children inherited it. Import it
explicitly before a bare fork of a task or callback process instead, so
each child does not import it again. If the import fails there, the
child imports it again and reports the error in its own log, as before.
(cherry picked from commit f46a370)

Co-authored-by: Kaxil Naik <kaxilnaik@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants