@@ -156,6 +156,7 @@ def _run(self) -> Generator[NodeEvent | InNodeEvent, None, None]:
156156 index = 0 ,
157157 pre_iteration_output = None ,
158158 )
159+ iter_run_map : dict [str , float ] = {}
159160 outputs : list [Any ] = [None ] * len (iterator_list_value )
160161 try :
161162 if self .node_data .is_parallel :
@@ -175,6 +176,7 @@ def _run(self) -> Generator[NodeEvent | InNodeEvent, None, None]:
175176 iteration_graph ,
176177 index ,
177178 item ,
179+ iter_run_map ,
178180 )
179181 future .add_done_callback (thread_pool .task_done_callback )
180182 futures .append (future )
@@ -213,6 +215,7 @@ def _run(self) -> Generator[NodeEvent | InNodeEvent, None, None]:
213215 start_at ,
214216 graph_engine ,
215217 iteration_graph ,
218+ iter_run_map ,
216219 )
217220 if self .node_data .error_handle_mode == ErrorHandleMode .REMOVE_ABNORMAL_OUTPUT :
218221 outputs = [output for output in outputs if output is not None ]
@@ -230,7 +233,9 @@ def _run(self) -> Generator[NodeEvent | InNodeEvent, None, None]:
230233
231234 yield RunCompletedEvent (
232235 run_result = NodeRunResult (
233- status = WorkflowNodeExecutionStatus .SUCCEEDED , outputs = {"output" : jsonable_encoder (outputs )}
236+ status = WorkflowNodeExecutionStatus .SUCCEEDED ,
237+ outputs = {"output" : jsonable_encoder (outputs )},
238+ metadata = {NodeRunMetadataKey .ITERATION_DURATION_MAP : iter_run_map },
234239 )
235240 )
236241 except IterationNodeError as e :
@@ -356,15 +361,19 @@ def _run_single_iter(
356361 start_at : datetime ,
357362 graph_engine : "GraphEngine" ,
358363 iteration_graph : Graph ,
364+ iter_run_map : dict [str , float ],
359365 parallel_mode_run_id : Optional [str ] = None ,
360366 ) -> Generator [NodeEvent | InNodeEvent , None , None ]:
361367 """
362368 run single iteration
363369 """
370+ iter_start_at = datetime .now (timezone .utc ).replace (tzinfo = None )
371+
364372 try :
365373 rst = graph_engine .run ()
366374 # get current iteration index
367375 current_index = variable_pool .get ([self .node_id , "index" ]).value
376+ iteration_run_id = parallel_mode_run_id if parallel_mode_run_id is not None else f"{ current_index } "
368377 next_index = int (current_index ) + 1
369378
370379 if current_index is None :
@@ -431,6 +440,8 @@ def _run_single_iter(
431440 variable_pool .add ([self .node_id , "index" ], next_index )
432441 if next_index < len (iterator_list_value ):
433442 variable_pool .add ([self .node_id , "item" ], iterator_list_value [next_index ])
443+ duration = (datetime .now (timezone .utc ).replace (tzinfo = None ) - iter_start_at ).total_seconds ()
444+ iter_run_map [iteration_run_id ] = duration
434445 yield IterationRunNextEvent (
435446 iteration_id = self .id ,
436447 iteration_node_id = self .node_id ,
@@ -439,6 +450,7 @@ def _run_single_iter(
439450 index = next_index ,
440451 parallel_mode_run_id = parallel_mode_run_id ,
441452 pre_iteration_output = None ,
453+ duration = duration ,
442454 )
443455 return
444456 elif self .node_data .error_handle_mode == ErrorHandleMode .REMOVE_ABNORMAL_OUTPUT :
@@ -449,6 +461,8 @@ def _run_single_iter(
449461
450462 if next_index < len (iterator_list_value ):
451463 variable_pool .add ([self .node_id , "item" ], iterator_list_value [next_index ])
464+ duration = (datetime .now (timezone .utc ).replace (tzinfo = None ) - iter_start_at ).total_seconds ()
465+ iter_run_map [iteration_run_id ] = duration
452466 yield IterationRunNextEvent (
453467 iteration_id = self .id ,
454468 iteration_node_id = self .node_id ,
@@ -457,6 +471,7 @@ def _run_single_iter(
457471 index = next_index ,
458472 parallel_mode_run_id = parallel_mode_run_id ,
459473 pre_iteration_output = None ,
474+ duration = duration ,
460475 )
461476 return
462477 elif self .node_data .error_handle_mode == ErrorHandleMode .TERMINATED :
@@ -485,6 +500,8 @@ def _run_single_iter(
485500
486501 if next_index < len (iterator_list_value ):
487502 variable_pool .add ([self .node_id , "item" ], iterator_list_value [next_index ])
503+ duration = (datetime .now (timezone .utc ).replace (tzinfo = None ) - iter_start_at ).total_seconds ()
504+ iter_run_map [iteration_run_id ] = duration
488505 yield IterationRunNextEvent (
489506 iteration_id = self .id ,
490507 iteration_node_id = self .node_id ,
@@ -493,6 +510,7 @@ def _run_single_iter(
493510 index = next_index ,
494511 parallel_mode_run_id = parallel_mode_run_id ,
495512 pre_iteration_output = jsonable_encoder (current_iteration_output ) if current_iteration_output else None ,
513+ duration = duration ,
496514 )
497515
498516 except IterationNodeError as e :
@@ -528,6 +546,7 @@ def _run_single_iter_parallel(
528546 iteration_graph : Graph ,
529547 index : int ,
530548 item : Any ,
549+ iter_run_map : dict [str , float ],
531550 ) -> Generator [NodeEvent | InNodeEvent , None , None ]:
532551 """
533552 run single iteration in parallel mode
@@ -546,6 +565,7 @@ def _run_single_iter_parallel(
546565 start_at = start_at ,
547566 graph_engine = graph_engine_copy ,
548567 iteration_graph = iteration_graph ,
568+ iter_run_map = iter_run_map ,
549569 parallel_mode_run_id = parallel_mode_run_id ,
550570 ):
551571 q .put (event )
0 commit comments