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}