This is an automated email from the ASF dual-hosted git repository. pierrejeambrun pushed a commit to branch revert-62214-fix/thread-safe-auth-manager-init in repository https://gitbox.apache.org/repos/asf/airflow.git
commit cb13865745b376e81945c6a03eaf4b45d065ccc1 Author: Pierre Jeambrun <[email protected]> AuthorDate: Tue Feb 24 12:15:06 2026 +0100 Revert "Fix race condition in auth manager initialization (#62214)" This reverts commit 5c9171af1a56b5b60bb121537159ceb9c4de9f73. --- airflow-core/src/airflow/api_fastapi/app.py | 10 ++----- airflow-core/tests/unit/api_fastapi/test_app.py | 35 ---------------------- airflow-core/tests/unit/utils/test_db.py | 3 -- .../fab/auth_manager/cli_commands/utils.py | 3 -- .../unit/fab/auth_manager/api_fastapi/conftest.py | 2 -- .../fab/tests/unit/fab/auth_manager/conftest.py | 5 ---- .../unit/fab/auth_manager/test_fab_auth_manager.py | 6 ---- .../tests/unit/fab/auth_manager/test_security.py | 3 -- .../fab/auth_manager/views/test_permissions.py | 3 -- .../unit/fab/auth_manager/views/test_roles_list.py | 3 -- .../tests/unit/fab/auth_manager/views/test_user.py | 3 -- .../unit/fab/auth_manager/views/test_user_edit.py | 3 -- .../unit/fab/auth_manager/views/test_user_stats.py | 3 -- providers/fab/tests/unit/fab/www/test_auth.py | 3 -- .../fab/www/views/test_views_custom_user_views.py | 3 -- .../common/auth_backend/test_google_openid.py | 7 ----- .../unit/keycloak/auth_manager/routes/conftest.py | 3 +- 17 files changed, 3 insertions(+), 95 deletions(-) diff --git a/airflow-core/src/airflow/api_fastapi/app.py b/airflow-core/src/airflow/api_fastapi/app.py index 7367bdc5d67..30d151c0db7 100644 --- a/airflow-core/src/airflow/api_fastapi/app.py +++ b/airflow-core/src/airflow/api_fastapi/app.py @@ -17,7 +17,6 @@ from __future__ import annotations import logging -import threading from contextlib import AsyncExitStack, asynccontextmanager from functools import cache from typing import TYPE_CHECKING @@ -58,7 +57,6 @@ log = logging.getLogger(__name__) class _AuthManagerState: instance: BaseAuthManager | None = None - _lock = threading.Lock() @asynccontextmanager @@ -139,12 +137,8 @@ def get_auth_manager_cls() -> type[BaseAuthManager]: def create_auth_manager() -> BaseAuthManager: """Create the auth manager.""" - if _AuthManagerState.instance is not None: - return _AuthManagerState.instance - with _AuthManagerState._lock: - if _AuthManagerState.instance is None: - auth_manager_cls = get_auth_manager_cls() - _AuthManagerState.instance = auth_manager_cls() + auth_manager_cls = get_auth_manager_cls() + _AuthManagerState.instance = auth_manager_cls() return _AuthManagerState.instance diff --git a/airflow-core/tests/unit/api_fastapi/test_app.py b/airflow-core/tests/unit/api_fastapi/test_app.py index fa46a0d1f32..1eb692e1864 100644 --- a/airflow-core/tests/unit/api_fastapi/test_app.py +++ b/airflow-core/tests/unit/api_fastapi/test_app.py @@ -16,7 +16,6 @@ # under the License. from __future__ import annotations -import threading from unittest import mock import pytest @@ -119,37 +118,3 @@ def test_plugin_with_invalid_url_prefix(caplog, fastapi_apps, expected_message, assert any(expected_message in rec.message for rec in caplog.records) assert not any(r.path == invalid_path for r in app.routes) - - -def test_create_auth_manager_thread_safety(): - """Concurrent calls to create_auth_manager must return the same singleton instance.""" - call_count = 0 - singleton = None - - class FakeAuthManager: - def __init__(self): - nonlocal call_count, singleton - call_count += 1 - singleton = self - - app_module.purge_cached_app() - - results = [] - barrier = threading.Barrier(10) - - def call_create_auth_manager(): - barrier.wait() - results.append(app_module.create_auth_manager()) - - with mock.patch.object(app_module, "get_auth_manager_cls", return_value=FakeAuthManager): - threads = [threading.Thread(target=call_create_auth_manager) for _ in range(10)] - for t in threads: - t.start() - for t in threads: - t.join() - - assert len(results) == 10 - assert all(r is singleton for r in results) - assert call_count == 1 - - app_module.purge_cached_app() diff --git a/airflow-core/tests/unit/utils/test_db.py b/airflow-core/tests/unit/utils/test_db.py index 6a5a7b05061..2e2e49907a2 100644 --- a/airflow-core/tests/unit/utils/test_db.py +++ b/airflow-core/tests/unit/utils/test_db.py @@ -250,9 +250,6 @@ class TestDb: mock_upgrade = mocker.patch("alembic.command.upgrade") - from airflow.api_fastapi.app import purge_cached_app - - purge_cached_app() with conf_vars(auth): upgradedb() diff --git a/providers/fab/src/airflow/providers/fab/auth_manager/cli_commands/utils.py b/providers/fab/src/airflow/providers/fab/auth_manager/cli_commands/utils.py index d3459709572..6d2ed506930 100644 --- a/providers/fab/src/airflow/providers/fab/auth_manager/cli_commands/utils.py +++ b/providers/fab/src/airflow/providers/fab/auth_manager/cli_commands/utils.py @@ -29,7 +29,6 @@ from flask_sqlalchemy import SQLAlchemy from sqlalchemy.engine import make_url import airflow -from airflow.api_fastapi.app import purge_cached_app from airflow.configuration import conf from airflow.exceptions import AirflowConfigException from airflow.providers.fab.www.extensions.init_appbuilder import init_appbuilder @@ -51,8 +50,6 @@ def _return_appbuilder(app: Flask, db) -> AirflowAppBuilder: @contextmanager def get_application_builder() -> Generator[AirflowAppBuilder, None, None]: - _return_appbuilder.cache_clear() - purge_cached_app() static_folder = os.path.join(os.path.dirname(airflow.__file__), "www", "static") flask_app = Flask(__name__, static_folder=static_folder) webserver_config = conf.get_mandatory_value("fab", "config_file") diff --git a/providers/fab/tests/unit/fab/auth_manager/api_fastapi/conftest.py b/providers/fab/tests/unit/fab/auth_manager/api_fastapi/conftest.py index 27aafc3e117..fb884b8ede7 100644 --- a/providers/fab/tests/unit/fab/auth_manager/api_fastapi/conftest.py +++ b/providers/fab/tests/unit/fab/auth_manager/api_fastapi/conftest.py @@ -22,14 +22,12 @@ from contextlib import contextmanager import pytest from fastapi.testclient import TestClient -from airflow.api_fastapi.app import purge_cached_app from airflow.api_fastapi.core_api.security import get_user as get_user_dep from airflow.providers.fab.auth_manager.fab_auth_manager import FabAuthManager @pytest.fixture(scope="module") def fab_auth_manager(): - purge_cached_app() return FabAuthManager() diff --git a/providers/fab/tests/unit/fab/auth_manager/conftest.py b/providers/fab/tests/unit/fab/auth_manager/conftest.py index 0def443a7f3..2cad4b4db03 100644 --- a/providers/fab/tests/unit/fab/auth_manager/conftest.py +++ b/providers/fab/tests/unit/fab/auth_manager/conftest.py @@ -22,9 +22,7 @@ from pathlib import Path import pytest -from airflow.api_fastapi.app import purge_cached_app from airflow.providers.fab.www import app -from airflow.providers.fab.www.app import purge_cached_app as purge_fab_cached_app from tests_common.test_utils.config import conf_vars from unit.fab.decorators import dont_initialize_flask_app_submodules @@ -32,9 +30,6 @@ from unit.fab.decorators import dont_initialize_flask_app_submodules @pytest.fixture(scope="session") def minimal_app_for_auth_api(): - purge_cached_app() - purge_fab_cached_app() - @dont_initialize_flask_app_submodules( skip_all_except=[ "init_appbuilder", diff --git a/providers/fab/tests/unit/fab/auth_manager/test_fab_auth_manager.py b/providers/fab/tests/unit/fab/auth_manager/test_fab_auth_manager.py index 0e3bee5ed82..982a9ed3c75 100644 --- a/providers/fab/tests/unit/fab/auth_manager/test_fab_auth_manager.py +++ b/providers/fab/tests/unit/fab/auth_manager/test_fab_auth_manager.py @@ -160,12 +160,6 @@ def auth_manager(): @pytest.fixture def flask_app(): - from airflow.api_fastapi.app import purge_cached_app - - purge_cached_app() - from airflow.providers.fab.www.app import purge_cached_app as purge_fab_cached_app - - purge_fab_cached_app() with conf_vars( { ( diff --git a/providers/fab/tests/unit/fab/auth_manager/test_security.py b/providers/fab/tests/unit/fab/auth_manager/test_security.py index ce182dc6b4f..350101b832a 100644 --- a/providers/fab/tests/unit/fab/auth_manager/test_security.py +++ b/providers/fab/tests/unit/fab/auth_manager/test_security.py @@ -211,9 +211,6 @@ def clear_db_before_test(): @pytest.fixture(scope="module") def app(): - from airflow.api_fastapi.app import purge_cached_app - - purge_cached_app() with conf_vars( { ( diff --git a/providers/fab/tests/unit/fab/auth_manager/views/test_permissions.py b/providers/fab/tests/unit/fab/auth_manager/views/test_permissions.py index f53f621e28e..fc1af4dfb3a 100644 --- a/providers/fab/tests/unit/fab/auth_manager/views/test_permissions.py +++ b/providers/fab/tests/unit/fab/auth_manager/views/test_permissions.py @@ -30,9 +30,6 @@ from unit.fab.utils import client_with_login @pytest.fixture(scope="module") def fab_app(): - from airflow.api_fastapi.app import purge_cached_app - - purge_cached_app() with conf_vars( { ( diff --git a/providers/fab/tests/unit/fab/auth_manager/views/test_roles_list.py b/providers/fab/tests/unit/fab/auth_manager/views/test_roles_list.py index 50c7b2f0d2e..66192f919ad 100644 --- a/providers/fab/tests/unit/fab/auth_manager/views/test_roles_list.py +++ b/providers/fab/tests/unit/fab/auth_manager/views/test_roles_list.py @@ -30,9 +30,6 @@ from unit.fab.utils import client_with_login @pytest.fixture(scope="module") def fab_app(): - from airflow.api_fastapi.app import purge_cached_app - - purge_cached_app() with conf_vars( { ( diff --git a/providers/fab/tests/unit/fab/auth_manager/views/test_user.py b/providers/fab/tests/unit/fab/auth_manager/views/test_user.py index 383e90e1b28..1ae942824c7 100644 --- a/providers/fab/tests/unit/fab/auth_manager/views/test_user.py +++ b/providers/fab/tests/unit/fab/auth_manager/views/test_user.py @@ -30,9 +30,6 @@ from unit.fab.utils import client_with_login @pytest.fixture(scope="module") def fab_app(): - from airflow.api_fastapi.app import purge_cached_app - - purge_cached_app() with conf_vars( { ( diff --git a/providers/fab/tests/unit/fab/auth_manager/views/test_user_edit.py b/providers/fab/tests/unit/fab/auth_manager/views/test_user_edit.py index 0138af2703c..926753a04c2 100644 --- a/providers/fab/tests/unit/fab/auth_manager/views/test_user_edit.py +++ b/providers/fab/tests/unit/fab/auth_manager/views/test_user_edit.py @@ -30,9 +30,6 @@ from unit.fab.utils import client_with_login @pytest.fixture(scope="module") def fab_app(): - from airflow.api_fastapi.app import purge_cached_app - - purge_cached_app() with conf_vars( { ( diff --git a/providers/fab/tests/unit/fab/auth_manager/views/test_user_stats.py b/providers/fab/tests/unit/fab/auth_manager/views/test_user_stats.py index 0758f122ebd..9a68e9bc8fe 100644 --- a/providers/fab/tests/unit/fab/auth_manager/views/test_user_stats.py +++ b/providers/fab/tests/unit/fab/auth_manager/views/test_user_stats.py @@ -30,9 +30,6 @@ from unit.fab.utils import client_with_login @pytest.fixture(scope="module") def fab_app(): - from airflow.api_fastapi.app import purge_cached_app - - purge_cached_app() with conf_vars( { ( diff --git a/providers/fab/tests/unit/fab/www/test_auth.py b/providers/fab/tests/unit/fab/www/test_auth.py index a2b1bf9f3a0..7400ff2bf14 100644 --- a/providers/fab/tests/unit/fab/www/test_auth.py +++ b/providers/fab/tests/unit/fab/www/test_auth.py @@ -33,9 +33,6 @@ mock_call = Mock() @pytest.fixture def app(): - from airflow.api_fastapi.app import purge_cached_app - - purge_cached_app() with conf_vars( { ( diff --git a/providers/fab/tests/unit/fab/www/views/test_views_custom_user_views.py b/providers/fab/tests/unit/fab/www/views/test_views_custom_user_views.py index 9663f14fff4..2cfcb3f35fb 100644 --- a/providers/fab/tests/unit/fab/www/views/test_views_custom_user_views.py +++ b/providers/fab/tests/unit/fab/www/views/test_views_custom_user_views.py @@ -69,9 +69,6 @@ def delete_roles(app): @pytest.fixture def app(): - from airflow.api_fastapi.app import purge_cached_app - - purge_cached_app() with conf_vars( { ( diff --git a/providers/google/tests/unit/google/common/auth_backend/test_google_openid.py b/providers/google/tests/unit/google/common/auth_backend/test_google_openid.py index 7183e248993..fc91814441b 100644 --- a/providers/google/tests/unit/google/common/auth_backend/test_google_openid.py +++ b/providers/google/tests/unit/google/common/auth_backend/test_google_openid.py @@ -34,8 +34,6 @@ if not AIRFLOW_V_3_0_PLUS: allow_module_level=True, ) -from airflow.api_fastapi.app import purge_cached_app - from tests_common.test_utils.config import conf_vars @@ -44,11 +42,6 @@ def google_openid_app(): if importlib.util.find_spec("flask_session") is None: return None - purge_cached_app() - from airflow.providers.fab.www.app import purge_cached_app as purge_fab_cached_app - - purge_fab_cached_app() - def factory(): with conf_vars( { diff --git a/providers/keycloak/tests/unit/keycloak/auth_manager/routes/conftest.py b/providers/keycloak/tests/unit/keycloak/auth_manager/routes/conftest.py index 8706c569e0d..e5ea6131155 100644 --- a/providers/keycloak/tests/unit/keycloak/auth_manager/routes/conftest.py +++ b/providers/keycloak/tests/unit/keycloak/auth_manager/routes/conftest.py @@ -23,7 +23,7 @@ import pytest import time_machine from fastapi.testclient import TestClient -from airflow.api_fastapi.app import create_app, purge_cached_app +from airflow.api_fastapi.app import create_app from airflow.providers.keycloak.auth_manager.constants import ( CONF_CLIENT_ID_KEY, CONF_CLIENT_SECRET_KEY, @@ -40,7 +40,6 @@ if TYPE_CHECKING: @pytest.fixture def client(): - purge_cached_app() with conf_vars( { (
