huskies: merge 534_refactor_unify_timer_tick_watchdog_and_watcher_sweep_into_a_single_1_second_tick_loop
This commit is contained in:
+20
-49
@@ -19,7 +19,6 @@
|
||||
//! via exit-code inspection and silently skips the commit while still broadcasting
|
||||
//! the event so connected clients stay in sync.
|
||||
|
||||
use crate::config::{ProjectConfig, WatcherConfig};
|
||||
use crate::slog;
|
||||
use notify::{EventKind, RecommendedWatcher, RecursiveMode, Watcher, recommended_watcher};
|
||||
use serde::Serialize;
|
||||
@@ -328,7 +327,7 @@ fn flush_pending(
|
||||
/// All state is read from and written to CRDT — no filesystem access.
|
||||
/// Worktree pruning is handled separately by the CRDT event subscriber.
|
||||
pub(crate) fn sweep_done_to_archived(done_retention: Duration) {
|
||||
use crate::pipeline_state::{Stage, read_all_typed};
|
||||
use crate::pipeline_state::{PipelineEvent, Stage, stage_dir_name, transition, read_all_typed};
|
||||
|
||||
for item in read_all_typed() {
|
||||
if let Stage::Done { merged_at, .. } = &item.stage {
|
||||
@@ -337,9 +336,24 @@ pub(crate) fn sweep_done_to_archived(done_retention: Duration) {
|
||||
.to_std()
|
||||
.unwrap_or_default();
|
||||
if age >= done_retention {
|
||||
let story_id = &item.story_id.0;
|
||||
crate::db::move_item_stage(story_id, "6_archived", None);
|
||||
slog!("[watcher] sweep: promoted {story_id} → 6_archived/");
|
||||
let story_id = item.story_id.0.clone();
|
||||
match transition(item.stage.clone(), PipelineEvent::Accepted) {
|
||||
Ok(new_stage) => {
|
||||
crate::crdt_state::write_item(
|
||||
&story_id,
|
||||
stage_dir_name(&new_stage),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(false),
|
||||
None,
|
||||
);
|
||||
slog!("[watcher] sweep: promoted {story_id} → 6_archived/");
|
||||
}
|
||||
Err(e) => {
|
||||
slog!("[watcher] sweep: transition error for {story_id}: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,7 +374,6 @@ pub(crate) fn sweep_done_to_archived(done_retention: Duration) {
|
||||
pub fn start_watcher(
|
||||
git_root: PathBuf,
|
||||
event_tx: broadcast::Sender<WatcherEvent>,
|
||||
watcher_config: WatcherConfig,
|
||||
) {
|
||||
std::thread::spawn(move || {
|
||||
let (notify_tx, notify_rx) = mpsc::channel::<notify::Result<notify::Event>>();
|
||||
@@ -389,27 +402,13 @@ pub fn start_watcher(
|
||||
}
|
||||
}
|
||||
|
||||
slog!("[watcher] watching config files and running sweep timer");
|
||||
slog!("[watcher] watching config files for hot-reload");
|
||||
|
||||
const DEBOUNCE: Duration = Duration::from_millis(300);
|
||||
|
||||
// Mutable sweep config — hot-reloaded when project.toml changes.
|
||||
let mut sweep_interval = Duration::from_secs(watcher_config.sweep_interval_secs);
|
||||
let mut done_retention = Duration::from_secs(watcher_config.done_retention_secs);
|
||||
slog!(
|
||||
"[watcher] sweep_interval={}s done_retention={}s",
|
||||
watcher_config.sweep_interval_secs,
|
||||
watcher_config.done_retention_secs
|
||||
);
|
||||
|
||||
// Whether a config file change is pending in the current debounce window.
|
||||
let mut config_changed_pending = false;
|
||||
let mut deadline: Option<Instant> = None;
|
||||
// Track when we last swept 5_done/ → 6_archived/.
|
||||
// Initialise to "now minus interval" so the first sweep runs on startup.
|
||||
let mut last_sweep = Instant::now()
|
||||
.checked_sub(sweep_interval)
|
||||
.unwrap_or_else(Instant::now);
|
||||
|
||||
loop {
|
||||
// How long until the debounce window closes (or wait for next event).
|
||||
@@ -454,37 +453,9 @@ pub fn start_watcher(
|
||||
slog!("[watcher] broadcasting agent_config_changed");
|
||||
let _ = event_tx.send(WatcherEvent::ConfigChanged);
|
||||
|
||||
// Hot-reload sweep config from project.toml.
|
||||
match ProjectConfig::load(&git_root) {
|
||||
Ok(cfg) => {
|
||||
let new_sweep = Duration::from_secs(cfg.watcher.sweep_interval_secs);
|
||||
let new_retention =
|
||||
Duration::from_secs(cfg.watcher.done_retention_secs);
|
||||
if new_sweep != sweep_interval || new_retention != done_retention {
|
||||
slog!(
|
||||
"[watcher] hot-reload: sweep_interval={}s done_retention={}s",
|
||||
cfg.watcher.sweep_interval_secs,
|
||||
cfg.watcher.done_retention_secs
|
||||
);
|
||||
sweep_interval = new_sweep;
|
||||
done_retention = new_retention;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
slog!("[watcher] hot-reload: failed to parse config: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
config_changed_pending = false;
|
||||
}
|
||||
deadline = None;
|
||||
|
||||
// Periodically promote old items from 5_done/ to 6_archived/.
|
||||
let now = Instant::now();
|
||||
if now.duration_since(last_sweep) >= sweep_interval {
|
||||
last_sweep = now;
|
||||
sweep_done_to_archived(done_retention);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user