1- use std:: time:: Instant ;
2-
31use futures_lite:: StreamExt ;
42use prost:: Message ;
53use taurus_core:: runtime:: engine:: { EmitType , ExecutionEngine , ExecutionId , RespondEmitter } ;
@@ -14,13 +12,15 @@ use tucana::shared::execution_result;
1412use tucana:: shared:: { ExecutionFlow , ExecutionResult , NodeExecutionResult , Value } ;
1513
1614use crate :: client:: runtime_execution:: TaurusRuntimeExecutionService ;
15+ use crate :: telemetry:: { errors, metrics} ;
1716
1817pub fn spawn_worker (
1918 client : async_nats:: Client ,
2019 engine : ExecutionEngine ,
2120 nats_remote : NATSRemoteRuntime ,
2221 runtime_emitter : NATSRespondEmitter ,
2322 mut runtime_execution_service : Option < TaurusRuntimeExecutionService > ,
23+ flow_type : String ,
2424) -> JoinHandle < ( ) > {
2525 tokio:: spawn ( async move {
2626 let mut execution_subscription = match client
@@ -33,6 +33,12 @@ pub fn spawn_worker(
3333 }
3434 Err ( err) => {
3535 log:: error!( "Failed to subscribe to 'execution.*': {:?}" , err) ;
36+ errors:: record (
37+ "transport" ,
38+ "nats.subscribe" ,
39+ & err,
40+ "subject=execution.* queue=taurus" ,
41+ ) ;
3642 return ;
3743 }
3844 } ;
@@ -50,6 +56,7 @@ pub fn spawn_worker(
5056 & nats_remote,
5157 & runtime_emitter,
5258 runtime_execution_service. as_mut( ) ,
59+ flow_type. as_str( ) ,
5360 ) . await ;
5461 }
5562 None => {
@@ -71,6 +78,7 @@ async fn process_execution_message(
7178 nats_remote : & NATSRemoteRuntime ,
7279 runtime_emitter : & NATSRespondEmitter ,
7380 mut runtime_execution_service : Option < & mut TaurusRuntimeExecutionService > ,
81+ flow_type : & str ,
7482) {
7583 let requested_execution_id = parse_execution_id_from_subject ( & message. subject , "execution" )
7684 . unwrap_or_else ( || {
@@ -91,6 +99,16 @@ async fn process_execution_message(
9199 err,
92100 & message. payload
93101 ) ;
102+ errors:: record (
103+ "serialization" ,
104+ "execution_flow.decode" ,
105+ & err,
106+ format ! (
107+ "subject={} payload_bytes={}" ,
108+ message. subject,
109+ message. payload. len( )
110+ ) ,
111+ ) ;
94112 if let Some ( execution_service) = runtime_execution_service. as_mut ( ) {
95113 execution_service
96114 . update_runtime_execution ( build_decode_error_result ( requested_execution_id) )
@@ -101,6 +119,7 @@ async fn process_execution_message(
101119 } ;
102120
103121 let flow_id = flow. flow_id ;
122+ let function_identifiers = function_identifiers_by_node_id ( & flow) ;
104123 // Taurus app forwards all lifecycle events to emitter.
105124 // Direct request/reply responses remain disabled; delivery is emitter-only.
106125 let respond_emitter = |execution_id, emit_type : EmitType , value : Value | {
@@ -112,6 +131,8 @@ async fn process_execution_message(
112131 engine,
113132 Some ( nats_remote) ,
114133 Some ( & respond_emitter) ,
134+ flow_type,
135+ function_identifiers,
115136 )
116137 . await ;
117138 log:: debug!(
@@ -153,9 +174,12 @@ async fn execute_flow(
153174 engine : & ExecutionEngine ,
154175 remote : Option < & dyn RemoteRuntime > ,
155176 respond_emitter : Option < & dyn RespondEmitter > ,
177+ flow_type : & str ,
178+ function_identifiers : std:: collections:: HashMap < i64 , String > ,
156179) -> FlowRunResult {
157180 let started_at = now_unix_micros ( ) ;
158181 let flow_id = flow. flow_id ;
182+ let project_id = flow. project_id ;
159183 let input = flow. input_value . clone ( ) ;
160184 let report = engine
161185 . execute_flow_with_execution_id_report_async (
@@ -167,6 +191,16 @@ async fn execute_flow(
167191 )
168192 . await ;
169193 let finished_at = now_unix_micros ( ) ;
194+ record_flow_metrics (
195+ flow_id,
196+ project_id,
197+ flow_type,
198+ started_at,
199+ finished_at,
200+ & report. signal ,
201+ & report. node_execution_results ,
202+ & function_identifiers,
203+ ) ;
170204
171205 FlowRunResult {
172206 execution_id,
@@ -179,6 +213,67 @@ async fn execute_flow(
179213 }
180214}
181215
216+ fn function_identifiers_by_node_id ( flow : & ExecutionFlow ) -> std:: collections:: HashMap < i64 , String > {
217+ flow. node_functions
218+ . iter ( )
219+ . filter_map ( |function| {
220+ function
221+ . database_id
222+ . map ( |id| ( id, function. runtime_function_id . clone ( ) ) )
223+ } )
224+ . collect ( )
225+ }
226+
227+ fn record_flow_metrics (
228+ flow_id : i64 ,
229+ project_id : i64 ,
230+ flow_type : & str ,
231+ started_at : i64 ,
232+ finished_at : i64 ,
233+ signal : & Signal ,
234+ node_execution_results : & [ NodeExecutionResult ] ,
235+ function_identifiers : & std:: collections:: HashMap < i64 , String > ,
236+ ) {
237+ metrics:: flow_execution ( metrics:: FlowExecution {
238+ flow_id,
239+ project_id,
240+ flow_type,
241+ outcome : signal_outcome ( signal) ,
242+ duration_seconds : metrics:: duration_seconds ( started_at, finished_at) ,
243+ } ) ;
244+
245+ for result in node_execution_results {
246+ let node_id = metrics:: result_node_id ( result) ;
247+ let function_identifier = metrics:: result_function_identifier ( result)
248+ . map ( ToOwned :: to_owned)
249+ . or_else ( || node_id. and_then ( |id| function_identifiers. get ( & id) . cloned ( ) ) )
250+ . unwrap_or_else ( || "unknown" . to_string ( ) ) ;
251+ let ( error_code, error_category) = metrics:: node_result_error ( result) ;
252+
253+ metrics:: function_execution ( metrics:: FunctionExecution {
254+ flow_id,
255+ project_id,
256+ flow_type,
257+ function_identifier : function_identifier. as_str ( ) ,
258+ node_id,
259+ outcome : metrics:: node_result_outcome ( result) ,
260+ duration_seconds : metrics:: duration_seconds ( result. started_at , result. finished_at ) ,
261+ error_code,
262+ error_category,
263+ } ) ;
264+ }
265+ }
266+
267+ fn signal_outcome ( signal : & Signal ) -> & ' static str {
268+ match signal {
269+ Signal :: Success ( _) => "success" ,
270+ Signal :: Failure ( _) => "failure" ,
271+ Signal :: Return ( _) => "return" ,
272+ Signal :: Respond ( _) => "respond" ,
273+ Signal :: Stop => "stop" ,
274+ }
275+ }
276+
182277fn parse_execution_id_from_subject (
183278 subject : & async_nats:: Subject ,
184279 prefix : & str ,
@@ -327,7 +422,17 @@ mod tests {
327422 let flow = execution_flow_from_fixture ( fixture) ;
328423 let engine = ExecutionEngine :: new ( ) ;
329424
330- let run_result = execute_flow ( execution_id, flow, & engine, None , None ) . await ;
425+ let function_identifiers = function_identifiers_by_node_id ( & flow) ;
426+ let run_result = execute_flow (
427+ execution_id,
428+ flow,
429+ & engine,
430+ None ,
431+ None ,
432+ "test" ,
433+ function_identifiers,
434+ )
435+ . await ;
331436
332437 println ! (
333438 "started_at={} finished_at={} delta={}" ,
0 commit comments