Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d2ae047b1 | ||
|
|
3283362b36 | ||
|
|
ce27ef8b9e | ||
|
|
bf4937d116 |
2 changed files with 48 additions and 0 deletions
|
|
@ -263,6 +263,27 @@ impl Broker {
|
|||
Ok(u64::try_from(n.max(0)).unwrap_or(0))
|
||||
}
|
||||
|
||||
/// Returns true when the recipient already has at least one
|
||||
/// undelivered message from `sender` with exactly `body` in the
|
||||
/// broker. Used by the scheduler to skip re-delivery of the same
|
||||
/// scheduled prompt without blocking distinct schedules whose
|
||||
/// bodies differ.
|
||||
pub fn has_pending_with_body(
|
||||
&self,
|
||||
recipient: &str,
|
||||
sender: &str,
|
||||
body: &str,
|
||||
) -> Result<bool> {
|
||||
let conn = self.conn.lock().unwrap();
|
||||
let n: i64 = conn.query_row(
|
||||
"SELECT COUNT(*) FROM messages
|
||||
WHERE recipient = ?1 AND sender = ?2 AND body = ?3 AND delivered_at IS NULL",
|
||||
params![recipient, sender, body],
|
||||
|row| row.get(0),
|
||||
)?;
|
||||
Ok(n > 0)
|
||||
}
|
||||
|
||||
/// Long-poll variant of `recv_batch`: returns immediately if any
|
||||
/// row is pending (popping up to `max`); otherwise waits up to
|
||||
/// `timeout` for the broker to emit a `Sent { to: recipient }`
|
||||
|
|
@ -1254,3 +1275,4 @@ mod tests {
|
|||
assert!(pop_one(broker, "bob").is_none());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,31 @@ fn fire_schedule(coord: &Arc<Coordinator>, schedule: &Schedule, now: i64) {
|
|||
notify_operator_missing_target(coord, schedule, target);
|
||||
continue;
|
||||
}
|
||||
// Skip delivery if there is already an unread message from
|
||||
// "scheduled" waiting in this target's inbox. Prevents the same
|
||||
// scheduled prompt from stacking up when an agent is slow or
|
||||
// briefly offline, while still allowing distinct scheduled
|
||||
// messages (different body) to enqueue independently.
|
||||
match coord.broker.has_pending_with_body(target, "scheduled", &schedule.body) {
|
||||
Ok(true) => {
|
||||
tracing::debug!(
|
||||
schedule = schedule.id,
|
||||
%target,
|
||||
"scheduled_prompts: skipping — same body already pending for target"
|
||||
);
|
||||
let _ = coord.scheduled_prompts.record_target_result(
|
||||
schedule.id,
|
||||
target,
|
||||
now,
|
||||
"skipped: already pending",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!(schedule = schedule.id, %target, error = ?e, "has_pending_with_body failed");
|
||||
}
|
||||
Ok(false) => {}
|
||||
}
|
||||
let msg = Message {
|
||||
from: "scheduled".to_owned(),
|
||||
to: target.clone(),
|
||||
|
|
@ -359,3 +384,4 @@ async fn known_agents_async() -> std::collections::HashSet<String> {
|
|||
}
|
||||
out
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue