pub(in crate::outbox) struct PurgePublishedRowsParams {
pub(in crate::outbox) retention_ms: i64,
pub(in crate::outbox) batch_size: i64,
}
pub(in crate::outbox) async fn purge_published_rows<'e>(
executor: impl sqlx::PgExecutor<'e>,
params: PurgePublishedRowsParams,
) -> Result<u64, sqlx::Error> {
let result = sqlx::query!(
r#"DELETE FROM outbox WHERE id IN (
SELECT id FROM outbox
WHERE published_at IS NOT NULL
AND published_at < now() - ($1::bigint * interval '1 millisecond')
LIMIT $2
)
AND published_at IS NOT NULL
AND published_at < now() - ($1::bigint * interval '1 millisecond')"#,
params.retention_ms,
params.batch_size,
)
.execute(executor)
.await?;
Ok(result.rows_affected())
}
pub(in crate::outbox) struct PurgeDeadRetentionRowsParams {
pub(in crate::outbox) retention_ms: i64,
pub(in crate::outbox) batch_size: i64,
}
pub(in crate::outbox) async fn purge_dead_retention_rows<'e>(
executor: impl sqlx::PgExecutor<'e>,
params: PurgeDeadRetentionRowsParams,
) -> Result<u64, sqlx::Error> {
let result = sqlx::query!(
r#"DELETE FROM outbox WHERE id IN (
SELECT id FROM outbox
WHERE dead_at IS NOT NULL
AND dead_at < now() - ($1::bigint * interval '1 millisecond')
LIMIT $2
)
AND dead_at IS NOT NULL
AND dead_at < now() - ($1::bigint * interval '1 millisecond')"#,
params.retention_ms,
params.batch_size,
)
.execute(executor)
.await?;
Ok(result.rows_affected())
}
pub(in crate::outbox) struct PurgeExpiredSweepRowsParams<'a> {
pub(in crate::outbox) batch_size: i64,
pub(in crate::outbox) dead_reason: &'a str,
}
pub(in crate::outbox) async fn purge_expired_sweep_rows<'e>(
executor: impl sqlx::PgExecutor<'e>,
params: PurgeExpiredSweepRowsParams<'_>,
) -> Result<u64, sqlx::Error> {
let result = sqlx::query!(
r#"UPDATE outbox
SET dead_at = now(),
dead_reason = $2,
last_error = 'reliar: expired before publication',
locked_by = NULL,
claim_token = NULL,
updated_at = now()
WHERE id IN (
SELECT id FROM outbox
WHERE expires_at IS NOT NULL AND expires_at <= now()
AND published_at IS NULL AND dead_at IS NULL
AND (locked_by IS NULL OR available_at <= now())
LIMIT $1
)
AND published_at IS NULL AND dead_at IS NULL
AND (locked_by IS NULL OR available_at <= now())"#,
params.batch_size,
params.dead_reason,
)
.execute(executor)
.await?;
Ok(result.rows_affected())
}
pub(in crate::outbox) struct StatsRow {
pub(in crate::outbox) pending: i64,
pub(in crate::outbox) dead: i64,
pub(in crate::outbox) expired_pending: i64,
pub(in crate::outbox) oldest_pending_available_at: Option<time::OffsetDateTime>,
pub(in crate::outbox) as_of: time::OffsetDateTime,
}
pub(in crate::outbox) async fn stats_row<'e>(
executor: impl sqlx::PgExecutor<'e>,
) -> Result<StatsRow, sqlx::Error> {
sqlx::query_as!(
StatsRow,
r#"SELECT
(SELECT count(*) FROM outbox
WHERE published_at IS NULL AND dead_at IS NULL
AND available_at <= now()
AND (expires_at IS NULL OR expires_at > now())) AS "pending!",
(SELECT count(*) FROM outbox WHERE dead_at IS NOT NULL) AS "dead!",
(SELECT count(*) FROM outbox
WHERE published_at IS NULL AND dead_at IS NULL
AND expires_at IS NOT NULL AND expires_at <= now()) AS "expired_pending!",
(SELECT available_at FROM outbox
WHERE published_at IS NULL AND dead_at IS NULL
AND available_at <= now()
AND (expires_at IS NULL OR expires_at > now())
ORDER BY available_at, id LIMIT 1) AS oldest_pending_available_at,
now() AS "as_of!""#
)
.fetch_one(executor)
.await
}