broker: batch reminder delivery in single db transaction
This commit is contained in:
parent
3c672ed6b2
commit
931d4b26e7
2 changed files with 86 additions and 28 deletions
|
|
@ -27,8 +27,8 @@
|
|||
//! small and the bulky payload can be read out of band.
|
||||
//!
|
||||
//! Atomicity of the inbox INSERT + `reminders.sent_at` UPDATE is handled
|
||||
//! inside `Broker::deliver_reminder`; this module only computes the
|
||||
//! body string before calling it.
|
||||
//! inside `Broker::deliver_reminders_batch`; this module only computes the
|
||||
//! body strings before calling it.
|
||||
|
||||
use std::io::Write;
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
|
|
@ -75,9 +75,23 @@ fn tick(coord: &Arc<Coordinator>) {
|
|||
return;
|
||||
}
|
||||
};
|
||||
for (agent, id, message, file_path) in due {
|
||||
let body = prepare_body(&agent, &message, file_path.as_deref());
|
||||
if let Err(e) = coord.broker.deliver_reminder(id, &agent, &body) {
|
||||
if due.is_empty() {
|
||||
return;
|
||||
}
|
||||
// Resolve body strings (file-path writes / inline) before entering
|
||||
// the batch transaction so the DB lock is held as briefly as possible.
|
||||
let items: Vec<(i64, String, String)> = due
|
||||
.iter()
|
||||
.map(|(agent, id, message, file_path)| {
|
||||
let body = prepare_body(agent, message, file_path.as_deref());
|
||||
(*id, agent.clone(), body)
|
||||
})
|
||||
.collect();
|
||||
// Single-transaction batch: one DB lock acquisition for N reminders
|
||||
// instead of N sequential lock/unlock cycles.
|
||||
let results = coord.broker.deliver_reminders_batch(&items);
|
||||
for ((id, agent, _body), result) in items.iter().zip(results.iter()) {
|
||||
if let Err(e) = result {
|
||||
let reason = format!("{e:#}");
|
||||
tracing::warn!(
|
||||
reminder_id = id,
|
||||
|
|
@ -85,11 +99,8 @@ fn tick(coord: &Arc<Coordinator>) {
|
|||
error = %reason,
|
||||
"failed to deliver reminder"
|
||||
);
|
||||
// Persist the failure so the dashboard can surface it +
|
||||
// bump attempt_count. After MAX_REMINDER_ATTEMPTS the
|
||||
// row drops out of `get_due_reminders` and waits for
|
||||
// operator retry / cancel.
|
||||
if let Err(persist_err) = coord.broker.record_reminder_failure(id, &reason) {
|
||||
// Persist the failure so the dashboard can surface it.
|
||||
if let Err(persist_err) = coord.broker.record_reminder_failure(*id, &reason) {
|
||||
tracing::warn!(
|
||||
reminder_id = id,
|
||||
error = ?persist_err,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue