tests_fuzz/utils/
retry.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::future::Future;
16use std::time::Duration;
17
18use common_telemetry::warn;
19
20pub async fn retry_with_backoff<T, E, Fut, F>(
21    mut operation: F,
22    max_attempts: usize,
23    init_backoff: Duration,
24    max_backoff: Duration,
25) -> Result<T, E>
26where
27    F: FnMut() -> Fut,
28    Fut: Future<Output = Result<T, E>>,
29    E: std::fmt::Debug,
30{
31    let mut backoff = init_backoff;
32    for attempt in 0..max_attempts {
33        match operation().await {
34            Ok(result) => return Ok(result),
35            Err(err) if attempt + 1 == max_attempts => return Err(err),
36            Err(err) => {
37                let current_attempt = attempt + 1;
38                warn!(
39                    "Retryable operation failed, attempt: {}, max_attempts: {}, backoff: {:?}, error: {:?}",
40                    current_attempt, max_attempts, backoff, err
41                );
42                tokio::time::sleep(backoff).await;
43                backoff = std::cmp::min(backoff * 2, max_backoff);
44            }
45        }
46    }
47
48    panic!("retry loop should always return")
49}