Skip to main content

qubit_retry/options/
attempt_timeout_option.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! Per-attempt timeout option.
11//!
12
13use std::time::Duration;
14
15use serde::{
16    Deserialize,
17    Serialize,
18};
19
20use super::attempt_timeout_policy::AttemptTimeoutPolicy;
21
22/// Per-attempt timeout settings.
23///
24/// A timeout option combines the timeout duration with the policy selected when
25/// an attempt exceeds that duration.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
27pub struct AttemptTimeoutOption {
28    /// Timeout applied to each eligible attempt.
29    #[serde(with = "qubit_serde::serde::duration_millis")]
30    timeout: Duration,
31    /// Policy used when the attempt times out.
32    policy: AttemptTimeoutPolicy,
33}
34
35impl AttemptTimeoutOption {
36    /// Creates a per-attempt timeout option.
37    ///
38    /// # Parameters
39    /// - `timeout`: Maximum duration for one attempt.
40    /// - `policy`: Action selected when the timeout is reached.
41    ///
42    /// # Returns
43    /// A timeout option. Call [`AttemptTimeoutOption::validate`] before using
44    /// values that come from configuration or user input.
45    #[inline]
46    pub fn new(timeout: Duration, policy: AttemptTimeoutPolicy) -> Self {
47        Self { timeout, policy }
48    }
49
50    /// Creates a timeout option that retries timed-out attempts.
51    ///
52    /// # Parameters
53    /// - `timeout`: Maximum duration for one attempt.
54    ///
55    /// # Returns
56    /// A timeout option using [`AttemptTimeoutPolicy::Retry`].
57    #[inline]
58    pub fn retry(timeout: Duration) -> Self {
59        Self::new(timeout, AttemptTimeoutPolicy::Retry)
60    }
61
62    /// Creates a timeout option that aborts on the first timed-out attempt.
63    ///
64    /// # Parameters
65    /// - `timeout`: Maximum duration for one attempt.
66    ///
67    /// # Returns
68    /// A timeout option using [`AttemptTimeoutPolicy::Abort`].
69    #[inline]
70    pub fn abort(timeout: Duration) -> Self {
71        Self::new(timeout, AttemptTimeoutPolicy::Abort)
72    }
73
74    /// Returns the timeout duration.
75    ///
76    /// # Returns
77    /// Maximum duration allowed for one attempt.
78    #[inline]
79    pub fn timeout(&self) -> Duration {
80        self.timeout
81    }
82
83    /// Returns the timeout policy.
84    ///
85    /// # Returns
86    /// Policy selected when one attempt times out.
87    #[inline]
88    pub fn policy(&self) -> AttemptTimeoutPolicy {
89        self.policy
90    }
91
92    /// Returns a copy with another timeout policy.
93    ///
94    /// # Parameters
95    /// - `policy`: Replacement timeout policy.
96    ///
97    /// # Returns
98    /// A timeout option with the same duration and the new policy.
99    #[inline]
100    pub fn with_policy(self, policy: AttemptTimeoutPolicy) -> Self {
101        Self { policy, ..self }
102    }
103
104    /// Validates this timeout option.
105    ///
106    /// # Returns
107    /// `Ok(())` when the timeout can be used by an executor.
108    ///
109    /// # Errors
110    /// Returns an error when the timeout duration is zero.
111    pub fn validate(&self) -> Result<(), String> {
112        if self.timeout.is_zero() {
113            Err("attempt timeout must be greater than zero".to_string())
114        } else {
115            Ok(())
116        }
117    }
118}