use super::types::QueuedUserMessage;
use crate::db::NotifyQueueRepository;
use uuid::Uuid;
fn repo() -> Option<NotifyQueueRepository> {
crate::db::global_pool().map(|p| NotifyQueueRepository::new(p.clone()))
}
fn spawn_if_runtime<F>(future: F, what: &'static str)
where
F: std::future::Future<Output = ()> + Send + 'static,
{
match tokio::runtime::Handle::try_current() {
Ok(handle) => {
handle.spawn(future);
}
Err(_) => {
tracing::debug!(
target: "background_task",
"No tokio runtime live: skipping {what} (durable parking unavailable)"
);
}
}
}
pub(crate) fn persist(session_id: Uuid, msg: &QueuedUserMessage) {
let Some(repo) = repo() else {
return;
};
let (context_text, display_text) = (msg.context_text.clone(), msg.display_text.clone());
let (origin, bg_meta) = (msg.origin, msg.bg_meta.clone());
spawn_if_runtime(
async move {
if let Err(e) = repo
.record(
Uuid::new_v4(),
session_id,
&context_text,
&display_text,
origin,
bg_meta.as_ref(),
)
.await
{
tracing::error!(
target: "background_task",
"Could not persist undelivered push for session {session_id}: it rides \
the in-memory queue alone and the next restart will lose it: {e:#}"
);
}
},
"notify_queue persist",
);
}
pub(crate) async fn redeliver_persisted() -> usize {
let Some(repo) = repo() else {
return 0;
};
let rows = match repo.all().await {
Ok(rows) => rows,
Err(e) => {
tracing::error!(
target: "background_task",
"Could not read persisted notify-queue rows: {e:#}"
);
return 0;
}
};
let mut count = 0usize;
for row in rows {
let msg = QueuedUserMessage {
context_text: row.context_text.clone(),
display_text: row.display_text.clone(),
origin: row.origin,
bg_meta: row.bg_meta.clone(),
};
if super::restart_recovery::deliver_or_park(row.session_id, msg)
&& let Err(e) = repo.clear(row.id).await
{
tracing::error!(
target: "background_task",
"Delivered persisted push {} but could not clear its row; it may be \
re-delivered after the next restart: {e:#}",
row.id
);
}
count += 1;
}
count
}
pub(crate) fn clear_on_delivery(session_id: Uuid, msg: &QueuedUserMessage) {
let Some(repo) = repo() else {
return;
};
let (context_text, display_text) = (msg.context_text.clone(), msg.display_text.clone());
spawn_if_runtime(
async move {
if let Err(e) = repo
.clear_matching(session_id, &context_text, &display_text)
.await
{
tracing::warn!(
target: "background_task",
"Could not clear delivered push from the durable notify queue for \
session {session_id}: next boot may redeliver it (a duplicate, never \
a loss): {e:#}"
);
}
},
"notify_queue clear",
);
}