Skip to main content

haste_document_storage/
retry.rs

1//! Retry policy shared by backends.
2
3use std::{future::Future, time::Duration};
4
5use crate::error::StorageError;
6
7const MAX_ATTEMPTS: u32 = 4;
8const INITIAL_BACKOFF: Duration = Duration::from_millis(200);
9
10/// Runs `operation` until it succeeds or fails with a non-transient error,
11/// backing off exponentially for at most four tries. Backends wrap each
12/// request in this; `name` only labels the retry log line.
13///
14/// # Errors
15///
16/// Returns the last error from `operation` once it is not transient or the
17/// tries are used up.
18pub async fn with_retry<T, F, Fut>(name: &str, operation: F) -> Result<T, StorageError>
19where
20    F: Fn() -> Fut,
21    Fut: Future<Output = Result<T, StorageError>>,
22{
23    let mut attempt = 1;
24    let mut backoff = INITIAL_BACKOFF;
25    loop {
26        match operation().await {
27            Err(error) if attempt < MAX_ATTEMPTS && error.is_transient() => {
28                tracing::debug!(operation = name, attempt, %error, "retrying document storage call");
29                tokio::time::sleep(backoff).await;
30                attempt += 1;
31                backoff *= 2;
32            }
33            result => return result,
34        }
35    }
36}