nats nak w/ shared retry_backoff, exhausted log; no 'will retry' lie

This commit is contained in:
2026-10-26 01:52:28 +01:00
parent 56f3d1ac1b
commit dfa5e1a4db
5 changed files with 88 additions and 11 deletions

View File

@@ -155,6 +155,14 @@ pub trait AckHandle: Send + Sync {
async fn defer(&self, delay: std::time::Duration) -> Result<(), DomainError>;
}
/// Wait before retrying an event whose `attempt`-th delivery just failed:
/// 5s doubling per attempt, capped at 5 minutes. Every backend (SQLite queue,
/// JetStream nak, outbox relay) uses this one schedule.
pub fn retry_backoff(attempt: u32) -> std::time::Duration {
let secs = 5u64 * (1u64 << attempt.min(6));
std::time::Duration::from_secs(secs.min(300))
}
/// Stable identity of one queued event; the key for de-duplicating deliveries.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct EventId(uuid::Uuid);

View File

@@ -53,3 +53,13 @@ fn follow_requested_with_handle() {
}
));
}
#[test]
fn retry_backoff_doubles_from_ten_seconds_and_caps_at_five_minutes() {
use domain::events::retry_backoff;
use std::time::Duration;
let secs: Vec<u64> = (1..=8).map(|n| retry_backoff(n).as_secs()).collect();
assert_eq!(secs, [10, 20, 40, 80, 160, 300, 300, 300]);
assert_eq!(retry_backoff(0), Duration::from_secs(5));
assert_eq!(retry_backoff(u32::MAX), Duration::from_secs(300));
}