fix: defer blocked deliveries, claim owner token
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user