todos: reopen an acked keyed row when the caller says so
This commit is contained in:
parent
d5782965db
commit
1b72ed56ff
12 changed files with 158 additions and 45 deletions
|
|
@ -143,6 +143,7 @@ async fn emit_login_transitions(
|
|||
Some(format!("logged_in:{agent}")),
|
||||
format!("agent '{agent}' logged in"),
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
@ -174,6 +175,7 @@ async fn emit_login_transitions(
|
|||
Some(format!("needs_login:{agent}")),
|
||||
format!("agent '{agent}' needs login"),
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,8 +87,14 @@ async fn tick(coord: &Arc<Coordinator>) {
|
|||
/// upsert-by-key dedup the same job a now-removed
|
||||
/// `has_pending_with_body` broker check used to do — collapsing a
|
||||
/// re-fire of the *same schedule* against a target that hasn't
|
||||
/// reviewed the last one yet — and does it more precisely (keyed on
|
||||
/// schedule identity, not on the body happening to be byte-identical).
|
||||
/// reviewed the last one yet, keyed on schedule identity rather than on
|
||||
/// the body happening to be byte-identical. `deliver_to_target` also
|
||||
/// passes `reopen_if_acked = true`, so this collapse only applies while
|
||||
/// the previous fire is genuinely still sitting there un-reviewed — once
|
||||
/// the target acks it, the *next* fire reopens the row and wakes again
|
||||
/// even with an identical body, instead of silently staying quiet
|
||||
/// forever — a recurring schedule with a static body used to wake its
|
||||
/// target once, ever, and then look dead.
|
||||
async fn fire_schedule(coord: &Arc<Coordinator>, schedule: &Schedule, now: i64) {
|
||||
let known: std::collections::HashSet<String> = known_agents().await;
|
||||
for target_row in &schedule.targets {
|
||||
|
|
@ -158,7 +164,9 @@ async fn fire_schedule(coord: &Arc<Coordinator>, schedule: &Schedule, now: i64)
|
|||
/// to push into there), a `push_todo` otherwise, keyed on the
|
||||
/// schedule's own identity (`schedule:{schedule_id}`) so a re-fire
|
||||
/// against a target that hasn't reviewed the last one collapses via
|
||||
/// `push_todo`'s own upsert-by-key dedup. Shared by the periodic
|
||||
/// `push_todo`'s own upsert-by-key dedup — but `reopen_if_acked = true`
|
||||
/// means that collapse only holds while unreviewed; once acked, the next
|
||||
/// fire reopens regardless of whether the body changed. Shared by the periodic
|
||||
/// `fire_schedule` tick and the manual `fire_now` dashboard action —
|
||||
/// the only difference between them is what each caller does with the
|
||||
/// `Result` (log/prefix and per-target `last_result`/`FireNowReport`
|
||||
|
|
@ -188,6 +196,14 @@ async fn deliver_to_target(
|
|||
Some(format!("schedule:{schedule_id}")),
|
||||
body.to_owned(),
|
||||
Some("scheduled".to_owned()),
|
||||
// Each fire is a distinct occurrence, not a restatement of
|
||||
// a persisting condition — an agent that already acked the
|
||||
// *previous* firing hasn't acked *this* one, so an acked
|
||||
// row must reopen even when the body is byte-identical
|
||||
// (the common case: most schedules don't vary their text
|
||||
// per fire). See `Todos::upsert`'s doc comment for the
|
||||
// full reconciler-vs-event rationale.
|
||||
true,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue