pierrejeambrun commented on code in PR #61483:
URL: https://github.com/apache/airflow/pull/61483#discussion_r2783745753


##########
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:
   +1 for this, probably a module constant is better. (Yes I think it's 
guaranteed to be loaded, some other fn read conf to define default args, those 
are done a module level too)



##########
airflow-core/src/airflow/api_fastapi/core_api/routes/ui/dags.py:
##########
@@ -234,18 +234,48 @@ 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 FIX: Validate once per DAG, then extend with extra fields
+    dag_runs_by_dag_id: dict[str, DAGWithLatestDagRunsResponse] = {}
+    for dag in dags:
+        # Validate ORM to DAGResponse once (this computes file_token)
+        dag_response = DAGResponse.model_validate(dag)
+        # Construct DAGWithLatestDagRunsResponse directly from validated 
response
+        # Use model_construct with explicit field copying to avoid 
model_dump() overhead
+        # which would convert DagTagResponse objects to dicts
+        dag_runs_by_dag_id[dag.dag_id] = 
DAGWithLatestDagRunsResponse.model_construct(
+            # Fields from DAGResponse (keep objects as-is, don't serialize to 
dict)
+            dag_id=dag_response.dag_id,
+            dag_display_name=dag_response.dag_display_name,
+            is_paused=dag_response.is_paused,
+            is_stale=dag_response.is_stale,
+            last_parsed_time=dag_response.last_parsed_time,
+            last_parse_duration=dag_response.last_parse_duration,
+            last_expired=dag_response.last_expired,
+            bundle_name=dag_response.bundle_name,
+            bundle_version=dag_response.bundle_version,
+            relative_fileloc=dag_response.relative_fileloc,
+            fileloc=dag_response.fileloc,
+            description=dag_response.description,
+            timetable_summary=dag_response.timetable_summary,
+            timetable_description=dag_response.timetable_description,
+            tags=dag_response.tags,  # Keep as DagTagResponse objects
+            max_active_tasks=dag_response.max_active_tasks,
+            max_active_runs=dag_response.max_active_runs,
+            
max_consecutive_failed_dag_runs=dag_response.max_consecutive_failed_dag_runs,
+            
has_task_concurrency_limits=dag_response.has_task_concurrency_limits,
+            has_import_errors=dag_response.has_import_errors,
+            next_dagrun_logical_date=dag_response.next_dagrun_logical_date,
+            
next_dagrun_data_interval_start=dag_response.next_dagrun_data_interval_start,
+            
next_dagrun_data_interval_end=dag_response.next_dagrun_data_interval_end,
+            next_dagrun_run_after=dag_response.next_dagrun_run_after,
+            owners=dag_response.owners,
+            file_token=dag_response.file_token,  # Computed field - already 
computed
+            # Extra fields for DAGWithLatestDagRunsResponse
+            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,

Review Comment:
   Shouldn't this be valided too? A `DAGResponse` can be valid, but this extra 
fields can fail validation, and we're not checking.
   
   I would remove the `DAGResponse.model_validate` call and keep the 
`DAGWithLatestDagRunsResponse.model_validate` so we are sure that the final 
full object is validated `DAGWithLatestDagRunsResponse` 



-- 
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]

Reply via email to