huskies: merge 1156 story Periodic liveness tick so runtime freezes have a precise timestamp
This commit is contained in:
@@ -167,6 +167,11 @@ pub struct WatcherConfig {
|
||||
/// state diverged. Default: 30 seconds.
|
||||
#[serde(default = "default_reconcile_interval_secs")]
|
||||
pub reconcile_interval_secs: u64,
|
||||
/// How often (in seconds) the liveness tick task emits a heartbeat log line.
|
||||
/// Reduce if 5-second granularity causes noise; increase to quiet the logs.
|
||||
/// Default: 5 seconds.
|
||||
#[serde(default = "default_liveness_tick_secs")]
|
||||
pub liveness_tick_secs: u64,
|
||||
}
|
||||
|
||||
impl Default for WatcherConfig {
|
||||
@@ -175,6 +180,7 @@ impl Default for WatcherConfig {
|
||||
sweep_interval_secs: default_sweep_interval_secs(),
|
||||
done_retention_secs: default_done_retention_secs(),
|
||||
reconcile_interval_secs: default_reconcile_interval_secs(),
|
||||
liveness_tick_secs: default_liveness_tick_secs(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,6 +197,10 @@ fn default_reconcile_interval_secs() -> u64 {
|
||||
30
|
||||
}
|
||||
|
||||
fn default_liveness_tick_secs() -> u64 {
|
||||
5
|
||||
}
|
||||
|
||||
fn default_qa() -> String {
|
||||
"server".to_string()
|
||||
}
|
||||
|
||||
@@ -403,6 +403,15 @@ async fn main() -> Result<(), std::io::Error> {
|
||||
Some(event_buffer),
|
||||
);
|
||||
|
||||
// Permanent liveness heartbeat — stops when the tokio runtime freezes,
|
||||
// giving a precise timestamp of the freeze from the last [liveness] line.
|
||||
let liveness_tick_secs = startup_root
|
||||
.as_ref()
|
||||
.and_then(|r| config::ProjectConfig::load(r).ok())
|
||||
.map(|c| c.watcher.liveness_tick_secs)
|
||||
.unwrap_or(5);
|
||||
startup::tick_loop::spawn_liveness_tick(liveness_tick_secs);
|
||||
|
||||
// Unified 1-second background tick loop.
|
||||
startup::tick_loop::spawn_tick_loop(
|
||||
Arc::clone(&startup_agents),
|
||||
|
||||
@@ -192,6 +192,7 @@ mod tests {
|
||||
sweep_interval_secs: 30,
|
||||
done_retention_secs: 7200,
|
||||
reconcile_interval_secs: 30,
|
||||
liveness_tick_secs: 5,
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -226,6 +226,29 @@ pub(crate) fn spawn_tick_loop(
|
||||
});
|
||||
}
|
||||
|
||||
/// Spawn a permanent background task that emits a liveness heartbeat log line
|
||||
/// every `interval_secs` seconds on the main tokio runtime.
|
||||
///
|
||||
/// Running on the main runtime (not `spawn_blocking`) means the heartbeat stops
|
||||
/// the moment the runtime freezes, giving an exact timestamp of the freeze from
|
||||
/// the last `[liveness]` line in the logs.
|
||||
pub(crate) fn spawn_liveness_tick(interval_secs: u64) {
|
||||
let interval_secs = interval_secs.max(1);
|
||||
crate::slog!("[liveness] liveness tick started; cadence={interval_secs}s");
|
||||
tokio::spawn(async move {
|
||||
let duration = std::time::Duration::from_secs(interval_secs);
|
||||
let mut ticker = tokio::time::interval(duration);
|
||||
loop {
|
||||
ticker.tick().await;
|
||||
let ts = std::time::UNIX_EPOCH
|
||||
.elapsed()
|
||||
.unwrap_or_default()
|
||||
.as_secs();
|
||||
crate::slog!("[liveness] tokio runtime alive ts={ts}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Fire any due generic scheduled timers and re-arm recurring ones.
|
||||
///
|
||||
/// Called every second from the unified tick loop. Catch-up semantics: timers
|
||||
|
||||
Reference in New Issue
Block a user