huskies: merge 534_refactor_unify_timer_tick_watchdog_and_watcher_sweep_into_a_single_1_second_tick_loop
This commit is contained in:
+59
-11
@@ -323,19 +323,12 @@ async fn main() -> Result<(), std::io::Error> {
|
||||
let (watcher_tx, _) = broadcast::channel::<io::watcher::WatcherEvent>(1024);
|
||||
let agents = Arc::new(AgentPool::new(port, watcher_tx.clone()));
|
||||
|
||||
// Start the background watchdog that detects and cleans up orphaned Running agents.
|
||||
// When orphans are found, auto-assign is triggered to reassign free agents.
|
||||
let watchdog_root: Option<PathBuf> = app_state.project_root.lock().unwrap().clone();
|
||||
AgentPool::spawn_watchdog(Arc::clone(&agents), watchdog_root);
|
||||
|
||||
// Filesystem watcher: watches config files (project.toml, agents.toml) for
|
||||
// hot-reload and runs the CRDT-based done→archived sweep. Work-item pipeline
|
||||
// events are driven by CRDT state transitions via crdt_state::subscribe().
|
||||
// hot-reload. Work-item pipeline events are driven by CRDT state transitions
|
||||
// via crdt_state::subscribe(). Sweep (done→archived) is handled by the unified
|
||||
// background tick loop below.
|
||||
if let Some(ref root) = *app_state.project_root.lock().unwrap() {
|
||||
let watcher_config = config::ProjectConfig::load(root)
|
||||
.map(|c| c.watcher)
|
||||
.unwrap_or_default();
|
||||
io::watcher::start_watcher(root.clone(), watcher_tx.clone(), watcher_config);
|
||||
io::watcher::start_watcher(root.clone(), watcher_tx.clone());
|
||||
}
|
||||
|
||||
// Bridge CRDT state-transition events to the watcher broadcast channel.
|
||||
@@ -655,6 +648,8 @@ async fn main() -> Result<(), std::io::Error> {
|
||||
.unwrap_or_else(|| std::path::PathBuf::from("/tmp/huskies-timers.json")),
|
||||
));
|
||||
|
||||
let timer_store_for_tick = Arc::clone(&timer_store);
|
||||
|
||||
let ctx = AppContext {
|
||||
state: app_state,
|
||||
store,
|
||||
@@ -672,6 +667,59 @@ async fn main() -> Result<(), std::io::Error> {
|
||||
|
||||
let app = build_routes(ctx, whatsapp_ctx.clone(), slack_ctx.clone(), port);
|
||||
|
||||
// Unified 1-second background tick loop: fires due timers, detects orphaned
|
||||
// agents (watchdog), and promotes done→archived items (sweep). Replaces the
|
||||
// three separate background loops that previously ran independently.
|
||||
{
|
||||
let tick_agents = Arc::clone(&startup_agents);
|
||||
let tick_timer = timer_store_for_tick;
|
||||
let tick_root = startup_root.clone();
|
||||
let sweep_cfg = tick_root
|
||||
.as_ref()
|
||||
.and_then(|r| config::ProjectConfig::load(r).ok())
|
||||
.map(|c| c.watcher)
|
||||
.unwrap_or_default();
|
||||
let sweep_every = sweep_cfg.sweep_interval_secs.max(1);
|
||||
let done_retention = std::time::Duration::from_secs(sweep_cfg.done_retention_secs);
|
||||
let pending_count = tick_timer.list().len();
|
||||
crate::slog!("[tick] Unified tick loop started; {pending_count} pending timer(s)");
|
||||
tokio::spawn(async move {
|
||||
let mut interval = tokio::time::interval(std::time::Duration::from_secs(1));
|
||||
let mut tick_count: u64 = 0;
|
||||
loop {
|
||||
interval.tick().await;
|
||||
tick_count = tick_count.wrapping_add(1);
|
||||
|
||||
// Timer: fire due timers every second.
|
||||
if let Some(ref root) = tick_root {
|
||||
let result =
|
||||
crate::chat::timer::tick_once(&tick_timer, &tick_agents, root).await;
|
||||
if let Err(msg) = result {
|
||||
crate::slog_error!("[tick] Timer tick panicked: {msg}");
|
||||
}
|
||||
}
|
||||
|
||||
// Watchdog: detect orphaned Running agents every 30 ticks.
|
||||
if tick_count.is_multiple_of(30) {
|
||||
let found = tick_agents.run_watchdog_pass();
|
||||
if found > 0 {
|
||||
crate::slog!(
|
||||
"[tick] {found} orphaned agent(s) detected; triggering auto-assign."
|
||||
);
|
||||
if let Some(ref root) = tick_root {
|
||||
tick_agents.auto_assign_available_work(root).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sweep: promote done→archived every sweep_interval_secs ticks.
|
||||
if tick_count.is_multiple_of(sweep_every) {
|
||||
crate::io::watcher::sweep_done_to_archived(done_retention);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Optional Matrix bot: connect to the homeserver and start listening for
|
||||
// messages if `.huskies/bot.toml` is present and enabled.
|
||||
if let Some(ref root) = startup_root {
|
||||
|
||||
Reference in New Issue
Block a user