fix(#937): skip scheduled delivery if target already has pending scheduled message
This commit is contained in:
parent
42a7d2eb0a
commit
bf4937d116
2 changed files with 40 additions and 0 deletions
|
|
@ -263,6 +263,21 @@ impl Broker {
|
||||||
Ok(u64::try_from(n.max(0)).unwrap_or(0))
|
Ok(u64::try_from(n.max(0)).unwrap_or(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true when the recipient already has at least one
|
||||||
|
/// undelivered message from `sender` in the broker. Used by the
|
||||||
|
/// scheduler to avoid piling up repeated prompts when an agent is
|
||||||
|
/// slow or was briefly offline.
|
||||||
|
pub fn has_pending_from(&self, recipient: &str, sender: &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 delivered_at IS NULL",
|
||||||
|
params![recipient, sender],
|
||||||
|
|row| row.get(0),
|
||||||
|
)?;
|
||||||
|
Ok(n > 0)
|
||||||
|
}
|
||||||
|
|
||||||
/// Long-poll variant of `recv_batch`: returns immediately if any
|
/// Long-poll variant of `recv_batch`: returns immediately if any
|
||||||
/// row is pending (popping up to `max`); otherwise waits up to
|
/// row is pending (popping up to `max`); otherwise waits up to
|
||||||
/// `timeout` for the broker to emit a `Sent { to: recipient }`
|
/// `timeout` for the broker to emit a `Sent { to: recipient }`
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,31 @@ fn fire_schedule(coord: &Arc<Coordinator>, schedule: &Schedule, now: i64) {
|
||||||
notify_operator_missing_target(coord, schedule, target);
|
notify_operator_missing_target(coord, schedule, target);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Skip delivery if there is already an unread message from
|
||||||
|
// "scheduled" waiting in this target's inbox. Prevents prompt
|
||||||
|
// accumulation when the agent is slow to drain its queue or
|
||||||
|
// was briefly offline: at most one scheduled message is ever
|
||||||
|
// pending per target at a time.
|
||||||
|
match coord.broker.has_pending_from(target, "scheduled") {
|
||||||
|
Ok(true) => {
|
||||||
|
tracing::debug!(
|
||||||
|
schedule = schedule.id,
|
||||||
|
%target,
|
||||||
|
"scheduled_prompts: skipping — target already has pending scheduled message"
|
||||||
|
);
|
||||||
|
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_from failed");
|
||||||
|
}
|
||||||
|
Ok(false) => {}
|
||||||
|
}
|
||||||
let msg = Message {
|
let msg = Message {
|
||||||
from: "scheduled".to_owned(),
|
from: "scheduled".to_owned(),
|
||||||
to: target.clone(),
|
to: target.clone(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue