tirkarthi commented on code in PR #61483:
URL: https://github.com/apache/airflow/pull/61483#discussion_r2767333305
##########
airflow-core/src/airflow/api_fastapi/core_api/datamodels/dags.py:
##########
@@ -41,6 +42,19 @@
if TYPE_CHECKING:
from airflow.serialization.definitions.param import SerializedParamsDict
+
+@lru_cache(maxsize=1)
+def _get_file_token_serializer() -> URLSafeSerializer:
Review Comment:
Since the secret_key doesn't change could this be just set as a module level
private attribute instead of a cached function?
##########
airflow-core/src/airflow/api_fastapi/core_api/routes/ui/dags.py:
##########
@@ -234,18 +234,22 @@ def get_dags(
pending_actions_by_dag_id[dag_id].append(hitl_detail)
# aggregate rows by dag_id
- dag_runs_by_dag_id: dict[str, DAGWithLatestDagRunsResponse] = {
- dag.dag_id: DAGWithLatestDagRunsResponse.model_validate(
- {
- **DAGResponse.model_validate(dag).model_dump(),
- "asset_expression": dag.asset_expression,
- "latest_dag_runs": [],
- "pending_actions": pending_actions_by_dag_id[dag.dag_id],
- "is_favorite": dag.dag_id in favorite_dag_ids,
- }
+ # Performance optimization: Validate ORM to DAGResponse once per DAG, then
use model_construct
+ # to build DAGWithLatestDagRunsResponse without redundant validation.
+ # The original pattern (model_validate -> model_dump -> model_validate)
caused triple
+ # serialization overhead that scaled poorly with the number of DAGs.
+ dag_runs_by_dag_id: dict[str, DAGWithLatestDagRunsResponse] = {}
+ for dag in dags:
+ dag_response = DAGResponse.model_validate(dag)
+ dag_data = dag_response.model_dump()
+ dag_data["asset_expression"] = dag.asset_expression
+ dag_data["latest_dag_runs"] = []
+ dag_data["pending_actions"] = pending_actions_by_dag_id[dag.dag_id]
+ dag_data["is_favorite"] = dag.dag_id in favorite_dag_ids
+ dag_runs_by_dag_id[dag.dag_id] =
DAGWithLatestDagRunsResponse.model_construct(
Review Comment:
I see below traceback while testing dags with tags. Can you please test this
PR with dags that have tags? I tried the below patch but it would change the
signature to include dict.
```diff
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dags.py
b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dags.py
index cf0d69357a..5516cea9c8 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dags.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dags.py
@@ -102,7 +102,7 @@ class DAGResponse(BaseModel):
@field_serializer("tags")
def serialize_tags(self, tags: list[DagTagResponse]) ->
list[DagTagResponse]:
"""Sort tags alphabetically by name."""
- return sorted(tags, key=lambda tag: tag.name)
+ return sorted(tags, key=lambda tag: tag["name"] if isinstance(tag,
dict) else tag.name)
@field_validator("owners", mode="before")
@classmethod
```
```
ERROR: Exception in ASGI application
Traceback (most recent call last):
File
"/home/karthikeyan/stuff/python/airflow/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dags.py",
line 105, in serialize_tags
return sorted(tags, key=lambda tag: tag.name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/home/karthikeyan/stuff/python/airflow/airflow-core/src/airflow/api_fastapi/core_api/datamodels/dags.py",
line 105, in <lambda>
return sorted(tags, key=lambda tag: tag.name)
^^^^^^^^
AttributeError: 'dict' object has no attribute 'name'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py",
line 409, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/fastapi/applications.py",
line 1138, in __call__
await super().__call__(scope, receive, send)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/applications.py",
line 112, in __call__
await self.middleware_stack(scope, receive, send)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/middleware/errors.py",
line 187, in __call__
raise exc
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/middleware/errors.py",
line 165, in __call__
await self.app(scope, receive, _send)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/middleware/cors.py",
line 85, in __call__
await self.app(scope, receive, send)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/middleware/gzip.py",
line 22, in __call__
await self.app(scope, receive, send)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/middleware/base.py",
line 177, in __call__
with recv_stream, send_stream, collapse_excgroups():
File "/usr/lib/python3.11/contextlib.py", line 158, in __exit__
self.gen.throw(typ, value, traceback)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/_utils.py",
line 82, in collapse_excgroups
raise exc
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/middleware/base.py",
line 179, in __call__
response = await self.dispatch_func(request, call_next)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/home/karthikeyan/stuff/python/airflow/airflow-core/src/airflow/api_fastapi/auth/middlewares/refresh_token.py",
line 61, in dispatch
response = await call_next(request)
^^^^^^^^^^^^^^^^^^^^^^^^
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/middleware/base.py",
line 154, in call_next
raise app_exc
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/middleware/base.py",
line 141, in coro
await self.app(scope, receive_or_disconnect, send_no_error)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/middleware/exceptions.py",
line 62, in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py",
line 53, in wrapped_app
raise exc
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py",
line 42, in wrapped_app
await app(scope, receive, sender)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py",
line 18, in __call__
await self.app(scope, receive, send)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/routing.py",
line 715, in __call__
await self.middleware_stack(scope, receive, send)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/routing.py",
line 735, in app
await route.handle(scope, receive, send)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/routing.py",
line 288, in handle
await self.app(scope, receive, send)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/fastapi/routing.py",
line 115, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py",
line 53, in wrapped_app
raise exc
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py",
line 42, in wrapped_app
await app(scope, receive, sender)
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/fastapi/routing.py",
line 101, in app
response = await f(request)
^^^^^^^^^^^^^^^^
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/fastapi/routing.py",
line 377, in app
content = await serialize_response(
^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/fastapi/routing.py",
line 221, in serialize_response
return field.serialize(
^^^^^^^^^^^^^^^^
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/fastapi/_compat/v2.py",
line 197, in serialize
return self._type_adapter.dump_python(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/home/karthikeyan/stuff/python/airflow/.venv/lib/python3.11/site-packages/pydantic/type_adapter.py",
line 572, in dump_python
return self.serializer.to_python(
^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.PydanticSerializationError: Error calling
function `serialize_tags`: AttributeError: 'dict' object has no attribute 'name'
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]