This is an automated email from the ASF dual-hosted git repository.

pierrejeambrun pushed a commit to branch v3-1-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-1-test by this push:
     new 6fc7177a1fe Revert "[v3-1-test] Fix race condition in auth manager 
initialization (#62214…" (#62407)
6fc7177a1fe is described below

commit 6fc7177a1fef395b4bdb0f6cc06a4a6884101190
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Tue Feb 24 13:58:06 2026 +0100

    Revert "[v3-1-test] Fix race condition in auth manager initialization 
(#62214…" (#62407)
    
    This reverts commit 5605d32a9865f1d13076c493b7f26a1bef27df0a.
---
 airflow-core/src/airflow/api_fastapi/app.py        | 34 ++++++++++-----------
 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  | 28 -----------------
 .../common/auth_backend/test_google_openid.py      |  7 -----
 .../unit/keycloak/auth_manager/routes/conftest.py  |  3 +-
 17 files changed, 16 insertions(+), 131 deletions(-)

diff --git a/airflow-core/src/airflow/api_fastapi/app.py 
b/airflow-core/src/airflow/api_fastapi/app.py
index 02b27a9b5f1..7c05295807e 100644
--- a/airflow-core/src/airflow/api_fastapi/app.py
+++ b/airflow-core/src/airflow/api_fastapi/app.py
@@ -17,9 +17,7 @@
 from __future__ import annotations
 
 import logging
-import threading
 from contextlib import AsyncExitStack, asynccontextmanager
-from functools import cache
 from typing import TYPE_CHECKING, cast
 from urllib.parse import urlsplit
 
@@ -56,10 +54,8 @@ RESERVED_URL_PREFIXES = ["/api/v2", "/ui", "/execution"]
 
 log = logging.getLogger(__name__)
 
-
-class _AuthManagerState:
-    instance: BaseAuthManager | None = None
-    _lock = threading.Lock()
+app: FastAPI | None = None
+auth_manager: BaseAuthManager | None = None
 
 
 @asynccontextmanager
@@ -111,16 +107,19 @@ def create_app(apps: str = "all") -> FastAPI:
     return app
 
 
-@cache
 def cached_app(config=None, testing=False, apps="all") -> FastAPI:
     """Return cached instance of Airflow API app."""
-    return create_app(apps=apps)
+    global app
+    if not app:
+        app = create_app(apps=apps)
+    return app
 
 
 def purge_cached_app() -> None:
     """Remove the cached version of the app and auth_manager in global 
state."""
-    cached_app.cache_clear()
-    _AuthManagerState.instance = None
+    global app, auth_manager
+    app = None
+    auth_manager = None
 
 
 def get_auth_manager_cls() -> type[BaseAuthManager]:
@@ -141,13 +140,10 @@ 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()
-    return _AuthManagerState.instance
+    global auth_manager
+    auth_manager_cls = get_auth_manager_cls()
+    auth_manager = auth_manager_cls()
+    return auth_manager
 
 
 def init_auth_manager(app: FastAPI | None = None) -> BaseAuthManager:
@@ -165,12 +161,12 @@ def init_auth_manager(app: FastAPI | None = None) -> 
BaseAuthManager:
 
 def get_auth_manager() -> BaseAuthManager:
     """Return the auth manager, provided it's been initialized before."""
-    if _AuthManagerState.instance is None:
+    if auth_manager is None:
         raise RuntimeError(
             "Auth Manager has not been initialized yet. "
             "The `init_auth_manager` method needs to be called first."
         )
-    return _AuthManagerState.instance
+    return auth_manager
 
 
 def init_plugins(app: FastAPI) -> None:
diff --git a/airflow-core/tests/unit/api_fastapi/test_app.py 
b/airflow-core/tests/unit/api_fastapi/test_app.py
index 3ad7437c373..448d527ab6b 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 1b9e3062b90..d6a8d4c1d66 100644
--- a/airflow-core/tests/unit/utils/test_db.py
+++ b/airflow-core/tests/unit/utils/test_db.py
@@ -240,9 +240,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 f5e5ea9c790..174b3867ad0 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
@@ -28,7 +28,6 @@ from flask import Flask
 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
@@ -50,8 +49,6 @@ def _return_appbuilder(app: Flask) -> 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 4c7f566d395..86273a0af74 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
@@ -19,13 +19,11 @@ from __future__ import annotations
 import pytest
 from fastapi.testclient import TestClient
 
-from airflow.api_fastapi.app import purge_cached_app
 from airflow.providers.fab.auth_manager.fab_auth_manager import FabAuthManager
 
 
 @pytest.fixture(scope="module")
 def fab_auth_manager():
-    purge_cached_app()
     return FabAuthManager(None)
 
 
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 a60ed124664..85fb85dace9 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
@@ -159,12 +159,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 218677098c1..75dec27d8b2 100644
--- a/providers/fab/tests/unit/fab/auth_manager/test_security.py
+++ b/providers/fab/tests/unit/fab/auth_manager/test_security.py
@@ -203,9 +203,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 c33383e856d..52c67f57425 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 7f293aa85e2..4ef28203ef7 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 a8748b14d92..c56d5f7aa09 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 9b34aab2bb0..97e57d4fe28 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 6ebbf614c70..3671217e0fe 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 7559ecbb704..b20ee27bd34 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 9cafe982476..e63ce584e3b 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
@@ -63,34 +63,6 @@ PERMISSIONS_TESTS_PARAMS = [
 ]
 
 
-def delete_roles(app):
-    for role_name in ["role_edit_one_dag"]:
-        delete_role(app, role_name)
-
-
[email protected]
-def app():
-    from airflow.api_fastapi.app import purge_cached_app
-
-    purge_cached_app()
-    with conf_vars(
-        {
-            (
-                "core",
-                "auth_manager",
-            ): 
"airflow.providers.fab.auth_manager.fab_auth_manager.FabAuthManager",
-        }
-    ):
-        app = application.create_app(enable_plugins=False)
-        app.config["WTF_CSRF_ENABLED"] = False
-        yield app
-
-
[email protected]
-def client(app):
-    return app.test_client()
-
-
 class TestSecurity:
     @classmethod
     def setup_class(cls):
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 16ac6cc6ac0..4cc6ad386c0 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 bd6a40eb62a..1807778b86a 100644
--- a/providers/keycloak/tests/unit/keycloak/auth_manager/routes/conftest.py
+++ b/providers/keycloak/tests/unit/keycloak/auth_manager/routes/conftest.py
@@ -19,7 +19,7 @@ from __future__ import annotations
 import pytest
 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,
@@ -32,7 +32,6 @@ from tests_common.test_utils.config import conf_vars
 
 @pytest.fixture
 def client():
-    purge_cached_app()
     with conf_vars(
         {
             (

Reply via email to