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 abcac64f624 Add number of queries guard for ui structure (#58051)
(#58632)
abcac64f624 is described below
commit abcac64f624db48d352268e995b7302f6aa876f2
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Tue Nov 25 11:46:40 2025 +0100
Add number of queries guard for ui structure (#58051) (#58632)
(cherry picked from commit 213294e573e67a63d15d0254d5226817e4c94520)
---
.../airflow/api_fastapi/core_api/routes/ui/structure.py | 3 +++
.../unit/api_fastapi/core_api/routes/ui/test_structure.py | 15 +++++++++++----
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/structure.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/structure.py
index 1fba54ce543..709cd7b8a65 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/structure.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/ui/structure.py
@@ -18,6 +18,7 @@ from __future__ import annotations
from fastapi import Depends, HTTPException, status
from sqlalchemy import select
+from sqlalchemy.orm import joinedload
from airflow.api_fastapi.auth.managers.models.resource_details import
DagAccessEntity
from airflow.api_fastapi.common.db.common import SessionDep
@@ -31,6 +32,7 @@ from airflow.api_fastapi.core_api.services.ui.structure
import (
get_upstream_assets,
)
from airflow.api_fastapi.core_api.services.ui.task_group import
task_group_to_dict
+from airflow.models.dag import DagModel
from airflow.models.dag_version import DagVersion
from airflow.models.serialized_dag import SerializedDagModel
from airflow.utils.dag_edges import dag_edges
@@ -70,6 +72,7 @@ def structure_data(
select(SerializedDagModel)
.join(DagVersion)
.where(SerializedDagModel.dag_id == dag_id, DagVersion.version_number
== version_number)
+
.options(joinedload(SerializedDagModel.dag_model).joinedload(DagModel.task_outlet_asset_references)),
)
if serialized_dag is None:
raise HTTPException(
diff --git
a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_structure.py
b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_structure.py
index ea58e610813..f8dd0116c61 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_structure.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_structure.py
@@ -33,6 +33,7 @@ from airflow.providers.standard.sensors.external_task import
ExternalTaskSensor
from airflow.sdk import Metadata, task
from airflow.sdk.definitions.asset import Asset, AssetAlias, Dataset
+from tests_common.test_utils.asserts import assert_queries_count
from tests_common.test_utils.db import clear_db_assets, clear_db_runs
pytestmark = pytest.mark.db_test
@@ -207,7 +208,7 @@ def asset3_id(make_dags, asset3, session) -> str:
class TestStructureDataEndpoint:
@pytest.mark.parametrize(
- "params, expected",
+ ("params", "expected", "expected_queries_count"),
[
(
{"dag_id": DAG_ID},
@@ -264,6 +265,7 @@ class TestStructureDataEndpoint:
},
],
},
+ 3,
),
(
{
@@ -271,6 +273,7 @@ class TestStructureDataEndpoint:
"root": "unknown_task",
},
{"edges": [], "nodes": []},
+ 3,
),
(
{
@@ -295,6 +298,7 @@ class TestStructureDataEndpoint:
},
],
},
+ 3,
),
(
{"dag_id": DAG_ID_EXTERNAL_TRIGGER, "external_dependencies":
True},
@@ -333,12 +337,14 @@ class TestStructureDataEndpoint:
},
],
},
+ 10,
),
],
)
@pytest.mark.usefixtures("make_dags")
- def test_should_return_200(self, test_client, params, expected):
- response = test_client.get("/structure/structure_data", params=params)
+ def test_should_return_200(self, test_client, params, expected,
expected_queries_count):
+ with assert_queries_count(expected_queries_count):
+ response = test_client.get("/structure/structure_data",
params=params)
assert response.status_code == 200
assert response.json() == expected
@@ -528,7 +534,8 @@ class TestStructureDataEndpoint:
],
}
- response = test_client.get("/structure/structure_data", params=params)
+ with assert_queries_count(10):
+ response = test_client.get("/structure/structure_data",
params=params)
assert response.status_code == 200
assert response.json() == expected