Skip to main content

kcl_lib/
util.rs

1use crate::errors::IsRetryable;
2
3#[derive(Debug, Clone)]
4pub struct RetryConfig {
5    /// Number of retries to attempt when execution results in `EngineHangup` or
6    /// `EngineInternal`.
7    pub retries: usize,
8    /// Whether to print a message to stderr when a retry is attempted.
9    pub print_retries: bool,
10}
11
12impl Default for RetryConfig {
13    fn default() -> Self {
14        Self {
15            retries: 2,
16            print_retries: true,
17        }
18    }
19}
20
21/// If execution results in `EngineHangup` or `EngineInternal`, retry.
22///
23/// See the test variation of this: [`crate::test_util::execute_with_retries`].
24pub async fn execute_with_retries<F, Fut, T, E>(config: &RetryConfig, mut execute: F) -> Result<T, E>
25where
26    F: FnMut() -> Fut,
27    Fut: Future<Output = Result<T, E>>,
28    E: IsRetryable + std::fmt::Display,
29{
30    let mut retries_remaining = config.retries;
31    loop {
32        // Run the closure to execute.
33        let exec_result = execute().await;
34
35        if retries_remaining > 0
36            && let Err(error) = &exec_result
37            && error.is_retryable()
38        {
39            if config.print_retries {
40                // Ignore the disable-println feature.
41                std::eprintln!("Execute got {error}; retrying...");
42            }
43            retries_remaining -= 1;
44            continue;
45        }
46
47        return exec_result;
48    }
49}