@@ -6,7 +6,7 @@ use crate::{
66} ;
77use code0_flow:: flow_service:: FlowUpdateService ;
88use std:: { sync:: Arc , time:: Duration } ;
9- use tokio:: { signal, time:: sleep} ;
9+ use tokio:: { signal, task :: JoinHandle , time:: sleep} ;
1010use tonic:: transport:: Server ;
1111use tonic_health:: pb:: health_server:: HealthServer ;
1212use tucana:: shared:: { AdapterConfiguration , RuntimeFeature } ;
@@ -62,11 +62,12 @@ impl<C: LoadConfig> ServerRunner<C> {
6262 runtime_config : Vec < AdapterConfiguration > ,
6363 ) -> anyhow:: Result < ( ) > {
6464 let config = self . context . adapter_config . clone ( ) ;
65- let mut runtime_status_service: Option < DracoRuntimeStatusService > = None ;
65+ let mut runtime_status_service: Option < Arc < DracoRuntimeStatusService > > = None ;
66+ let mut runtime_status_heartbeat_task: Option < JoinHandle < ( ) > > = None ;
6667 log:: info!( "Starting Draco Variant: {}" , config. draco_variant) ;
6768
6869 if !config. is_static ( ) {
69- runtime_status_service = Some (
70+ runtime_status_service = Some ( Arc :: new (
7071 DracoRuntimeStatusService :: from_url (
7172 config. aquila_url . clone ( ) ,
7273 config. aquila_token . clone ( ) ,
@@ -75,7 +76,7 @@ impl<C: LoadConfig> ServerRunner<C> {
7576 runtime_config,
7677 )
7778 . await ,
78- ) ;
79+ ) ) ;
7980
8081 if let Some ( ser) = & runtime_status_service {
8182 ser. update_runtime_status_by_status (
@@ -148,6 +149,35 @@ impl<C: LoadConfig> ServerRunner<C> {
148149 tucana:: shared:: adapter_runtime_status:: Status :: Running ,
149150 )
150151 . await ;
152+
153+ if config. adapter_status_update_interval_seconds > 0 {
154+ let status_service = Arc :: clone ( ser) ;
155+ let update_interval_seconds = config. adapter_status_update_interval_seconds ;
156+ runtime_status_heartbeat_task = Some ( tokio:: spawn ( async move {
157+ let mut interval =
158+ tokio:: time:: interval ( Duration :: from_secs ( update_interval_seconds) ) ;
159+ interval. set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Skip ) ;
160+
161+ // First tick is immediate; consume it so heartbeats start after the interval.
162+ interval. tick ( ) . await ;
163+
164+ loop {
165+ interval. tick ( ) . await ;
166+ status_service
167+ . update_runtime_status_by_status (
168+ tucana:: shared:: adapter_runtime_status:: Status :: Running ,
169+ )
170+ . await ;
171+ }
172+ } ) ) ;
173+
174+ log:: info!(
175+ "Runtime status heartbeat started (interval={}s)" ,
176+ update_interval_seconds
177+ ) ;
178+ } else {
179+ log:: info!( "Runtime status heartbeat is disabled" ) ;
180+ }
151181 } ;
152182 log:: info!( "Draco successfully initialized." ) ;
153183
@@ -212,6 +242,15 @@ impl<C: LoadConfig> ServerRunner<C> {
212242 }
213243 }
214244 }
245+ if let Some ( handle) = runtime_status_heartbeat_task. take ( ) {
246+ handle. abort ( ) ;
247+ if let Err ( err) = handle. await {
248+ if !err. is_cancelled ( ) {
249+ log:: warn!( "Runtime status heartbeat task ended unexpectedly: {}" , err) ;
250+ }
251+ }
252+ }
253+
215254 if let Some ( ser) = & runtime_status_service {
216255 ser. update_runtime_status_by_status (
217256 tucana:: shared:: adapter_runtime_status:: Status :: Stopped ,
0 commit comments