Skip to main content

orbit_client_pool/
options.rs

1use std::time::Duration;
2
3use crate::OptionsError;
4
5/// Code-first operating policy for one process-local client pool.
6#[derive(Clone, Debug, Eq, PartialEq)]
7pub struct PoolOptions {
8    pub(crate) min_idle: usize,
9    pub(crate) max_idle: usize,
10    pub(crate) max_live: usize,
11    pub(crate) max_concurrency: usize,
12    pub(crate) max_waiting: usize,
13    pub(crate) acquire_timeout: Option<Duration>,
14    pub(crate) idle_timeout: Option<Duration>,
15    pub(crate) max_lifetime: Option<Duration>
16}
17
18impl PoolOptions {
19    /// Declare every capacity value explicitly. Constructing options performs no IO.
20    pub const fn new(
21        min_idle: usize,
22        max_idle: usize,
23        max_live: usize,
24        max_concurrency: usize,
25        max_waiting: usize
26    ) -> Self {
27        Self {
28            min_idle,
29            max_idle,
30            max_live,
31            max_concurrency,
32            max_waiting,
33            acquire_timeout: None,
34            idle_timeout: None,
35            max_lifetime: None
36        }
37    }
38
39    /// Bound admission waits. `None` declares an indefinite wait.
40    pub const fn acquire_timeout(
41        mut self,
42        timeout: Option<Duration>
43    ) -> Self {
44        self.acquire_timeout = timeout;
45        self
46    }
47
48    /// Retire an unused client after the declared duration.
49    pub const fn idle_timeout(
50        mut self,
51        timeout: Option<Duration>
52    ) -> Self {
53        self.idle_timeout = timeout;
54        self
55    }
56
57    /// Retire a client after the declared total lifetime.
58    pub const fn max_lifetime(
59        mut self,
60        lifetime: Option<Duration>
61    ) -> Self {
62        self.max_lifetime = lifetime;
63        self
64    }
65
66    pub(crate) fn validate(&self) -> Result<(), OptionsError> {
67        validate(
68            self.min_idle,
69            self.max_idle,
70            self.max_live,
71            self.max_concurrency,
72            self.acquire_timeout,
73            self.idle_timeout,
74            self.max_lifetime
75        )
76    }
77}
78
79/// Code-first operating policy for one fleet-wide client profile.
80#[cfg(feature = "fleet")]
81#[derive(Clone, Debug, Eq, PartialEq)]
82pub struct FleetPoolOptions {
83    pub(crate) min_idle: u32,
84    pub(crate) max_idle: u32,
85    pub(crate) max_live: u32,
86    pub(crate) max_concurrency: u32,
87    pub(crate) max_waiting: usize,
88    pub(crate) acquire_timeout: Option<Duration>,
89    pub(crate) idle_timeout: Option<Duration>,
90    pub(crate) max_lifetime: Option<Duration>,
91    pub(crate) attempts: u32
92}
93
94#[cfg(feature = "fleet")]
95impl FleetPoolOptions {
96    /// Declare every capacity value and the lost-race attempt budget explicitly.
97    pub const fn new(
98        min_idle: u32,
99        max_idle: u32,
100        max_live: u32,
101        max_concurrency: u32,
102        max_waiting: usize,
103        attempts: u32
104    ) -> Self {
105        Self {
106            min_idle,
107            max_idle,
108            max_live,
109            max_concurrency,
110            max_waiting,
111            acquire_timeout: None,
112            idle_timeout: None,
113            max_lifetime: None,
114            attempts
115        }
116    }
117
118    /// Bound admission waits. `None` declares an indefinite wait.
119    pub const fn acquire_timeout(
120        mut self,
121        timeout: Option<Duration>
122    ) -> Self {
123        self.acquire_timeout = timeout;
124        self
125    }
126
127    /// Retire a locally owned unused client after the declared duration.
128    pub const fn idle_timeout(
129        mut self,
130        timeout: Option<Duration>
131    ) -> Self {
132        self.idle_timeout = timeout;
133        self
134    }
135
136    /// Retire a locally owned client after the declared total lifetime.
137    pub const fn max_lifetime(
138        mut self,
139        lifetime: Option<Duration>
140    ) -> Self {
141        self.max_lifetime = lifetime;
142        self
143    }
144
145    pub(crate) fn validate(&self) -> Result<(), OptionsError> {
146        validate(
147            self.min_idle as usize,
148            self.max_idle as usize,
149            self.max_live as usize,
150            self.max_concurrency as usize,
151            self.acquire_timeout,
152            self.idle_timeout,
153            self.max_lifetime
154        )?;
155        if self.attempts == 0 {
156            return Err(OptionsError::ZeroAttempts);
157        }
158        Ok(())
159    }
160
161    pub(crate) fn local_options(&self) -> PoolOptions {
162        PoolOptions::new(
163            0,
164            self.max_live as usize,
165            self.max_live as usize,
166            self.max_live as usize,
167            self.max_waiting
168        )
169        .acquire_timeout(self.acquire_timeout)
170        .idle_timeout(self.idle_timeout)
171        .max_lifetime(self.max_lifetime)
172    }
173}
174
175fn validate(
176    min_idle: usize,
177    max_idle: usize,
178    max_live: usize,
179    max_concurrency: usize,
180    acquire_timeout: Option<Duration>,
181    idle_timeout: Option<Duration>,
182    max_lifetime: Option<Duration>
183) -> Result<(), OptionsError> {
184    if max_live == 0 {
185        return Err(OptionsError::ZeroMaxLive);
186    }
187    if max_concurrency == 0 {
188        return Err(OptionsError::ZeroMaxConcurrency);
189    }
190    if min_idle > max_idle || max_idle > max_live {
191        return Err(OptionsError::CapacityOrder { min_idle, max_idle, max_live });
192    }
193    for (name, value) in [
194        ("acquire_timeout", acquire_timeout),
195        ("idle_timeout", idle_timeout),
196        ("max_lifetime", max_lifetime)
197    ] {
198        if value.is_some_and(|duration| duration.is_zero()) {
199            return Err(OptionsError::ZeroDuration(name));
200        }
201    }
202    Ok(())
203}