fix: defer blocked deliveries, claim owner token

This commit is contained in:
2026-10-26 00:33:29 +01:00
parent 53892847f2
commit 0236a488fa
13 changed files with 528 additions and 80 deletions

View File

@@ -259,6 +259,22 @@ impl AckHandle for DbAckHandle {
}
Ok(())
}
async fn defer(&self, delay: std::time::Duration) -> Result<(), DomainError> {
let secs = delay.as_secs_f64().ceil().max(1.0) as i64;
let sql = format!(
"UPDATE event_queue
SET status = 'pending', claimed_at = NULL, last_error = 'deferred',
next_attempt_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now', '+{secs} seconds')
WHERE id = ?"
);
sqlx::query(&sql)
.bind(self.row_id)
.execute(&self.pool)
.await
.map_err(|e| DomainError::InfrastructureError(format!("defer: {e}")))?;
Ok(())
}
}
fn backoff_seconds(attempts: i32) -> i64 {

View File

@@ -189,6 +189,33 @@ mod identity {
assert!(envelope.id().is_none());
}
#[tokio::test]
async fn defer_reschedules_without_counting_an_attempt() {
let (q, pool) = queue().await;
q.publish(&event()).await.unwrap();
let envelope = q.consume().next().await.unwrap().unwrap();
envelope
.defer(std::time::Duration::from_secs(600))
.await
.unwrap();
let (status, attempts, claimed, due_in): (String, i32, Option<String>, i64) =
sqlx::query_as(
"SELECT status, attempts, claimed_at,
CAST(strftime('%s', next_attempt_at) AS INTEGER)
- CAST(strftime('%s', 'now') AS INTEGER)
FROM event_queue",
)
.fetch_one(&pool)
.await
.unwrap();
assert_eq!(status, "pending");
assert_eq!(attempts, 0, "a deferral is not a failed attempt");
assert!(claimed.is_none(), "claim is released");
assert!((595..=600).contains(&due_in), "due in {due_in}s");
}
}
mod lease {