chrono_machines 0.5.2 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -43,12 +43,36 @@ pub mod policy;
43
43
  pub mod retry;
44
44
  pub mod sleep;
45
45
 
46
+ /// The `rand` crate this one was built against.
47
+ ///
48
+ /// [`BackoffStrategy::delay`] is generic over [`rand::Rng`], which puts that
49
+ /// trait in the public API: a downstream strategy cannot be written without
50
+ /// naming it. Re-exporting it here means implementors do not have to add their
51
+ /// own `rand` dependency and keep its version in lockstep with this crate's by
52
+ /// hand — a mismatch there produces two incompatible `Rng` traits and an error
53
+ /// that says nothing about the real cause.
54
+ ///
55
+ /// ```rust
56
+ /// use chrono_machines::{rand::Rng, BackoffStrategy};
57
+ ///
58
+ /// struct Immediate;
59
+ ///
60
+ /// impl BackoffStrategy for Immediate {
61
+ /// fn delay<R: Rng>(&self, attempt: u8, _rng: &mut R) -> Option<u64> {
62
+ /// self.should_retry(attempt).then_some(0)
63
+ /// }
64
+ /// fn should_retry(&self, attempt: u8) -> bool { attempt < self.max_attempts() }
65
+ /// fn max_attempts(&self) -> u8 { 3 }
66
+ /// }
67
+ /// ```
68
+ pub use ::rand;
69
+
46
70
  pub use backoff::{
47
- fibonacci, BackoffPolicy, BackoffStrategy, ConstantBackoff, ExponentialBackoff,
48
- FibonacciBackoff,
71
+ BackoffPolicy, BackoffStrategy, ConstantBackoff, ExponentialBackoff, FibonacciBackoff,
72
+ fibonacci,
49
73
  };
50
74
  #[cfg(feature = "std")]
51
- pub use dsl::{builder_for_policy, retry_with_policy, DslError};
75
+ pub use dsl::{DslError, builder_for_policy, retry_with_policy};
52
76
  #[cfg(any(feature = "std", feature = "alloc"))]
53
77
  pub use policy::PolicyRegistry;
54
78
  #[cfg(feature = "std")]
@@ -56,15 +80,21 @@ pub use policy::{
56
80
  clear_global_policies, get_global_policy, list_global_policies, register_global_policy,
57
81
  remove_global_policy,
58
82
  };
83
+ #[cfg(feature = "async")]
84
+ pub use retry::AsyncRetryable;
59
85
  #[cfg(any(feature = "std", feature = "alloc"))]
60
- pub use retry::{RetryBuilder, RetryContext, RetryError, RetryOutcome, Retryable, RetryableExt};
86
+ pub use retry::{
87
+ DelayHint, RetryBuilder, RetryContext, RetryError, RetryOutcome, Retryable, RetryableExt,
88
+ };
89
+ #[cfg(feature = "async")]
90
+ pub use sleep::AsyncSleeper;
61
91
  #[cfg(feature = "std")]
62
92
  pub use sleep::StdSleeper;
63
93
  pub use sleep::{FnSleeper, Sleeper};
64
94
 
95
+ use rand::RngExt;
65
96
  #[cfg(feature = "std")]
66
97
  use rand::rngs::StdRng;
67
- use rand::RngExt;
68
98
 
69
99
  use rand::Rng;
70
100
 
@@ -209,147 +239,4 @@ impl Default for Policy {
209
239
  }
210
240
 
211
241
  #[cfg(test)]
212
- mod tests {
213
- use super::*;
214
- use rand::rngs::StdRng;
215
- use rand::SeedableRng;
216
-
217
- #[test]
218
- fn test_policy_default() {
219
- let policy = Policy::default();
220
- assert_eq!(policy.max_attempts, 3);
221
- assert_eq!(policy.base_delay_ms, 100);
222
- assert_eq!(policy.multiplier, 2.0);
223
- assert_eq!(policy.max_delay_ms, 10_000);
224
- }
225
-
226
- #[test]
227
- fn test_calculate_delay_bounds() {
228
- let policy = Policy {
229
- max_attempts: 5,
230
- base_delay_ms: 100,
231
- multiplier: 2.0,
232
- max_delay_ms: 1000,
233
- };
234
-
235
- let mut rng = StdRng::seed_from_u64(42);
236
-
237
- // First attempt with full jitter: delay should be between 0 and 100ms
238
- let delay1 = policy.calculate_delay_with_rng(1, 1.0, &mut rng);
239
- assert!(delay1 <= 100);
240
-
241
- // Second attempt with full jitter: delay should be between 0 and 200ms
242
- let delay2 = policy.calculate_delay_with_rng(2, 1.0, &mut rng);
243
- assert!(delay2 <= 200);
244
-
245
- // Fifth attempt with full jitter: delay should be capped at max_delay_ms (1000ms)
246
- let delay5 = policy.calculate_delay_with_rng(5, 1.0, &mut rng);
247
- assert!(delay5 <= 1000);
248
- }
249
-
250
- #[test]
251
- fn test_should_retry() {
252
- let policy = Policy {
253
- max_attempts: 3,
254
- ..Policy::default()
255
- };
256
-
257
- assert!(policy.should_retry(1));
258
- assert!(policy.should_retry(2));
259
- assert!(!policy.should_retry(3));
260
- assert!(!policy.should_retry(4));
261
- }
262
-
263
- #[test]
264
- fn test_max_delay_cap() {
265
- let policy = Policy {
266
- max_attempts: 10,
267
- base_delay_ms: 100,
268
- multiplier: 2.0,
269
- max_delay_ms: 500,
270
- };
271
-
272
- let mut rng = StdRng::seed_from_u64(42);
273
-
274
- // High attempt number should still be capped
275
- let delay = policy.calculate_delay_with_rng(10, 1.0, &mut rng);
276
- assert!(delay <= 500);
277
- }
278
-
279
- #[test]
280
- fn test_zero_multiplier() {
281
- let policy = Policy {
282
- max_attempts: 5,
283
- base_delay_ms: 100,
284
- multiplier: 1.0, // No exponential growth
285
- max_delay_ms: 10_000,
286
- };
287
-
288
- let mut rng = StdRng::seed_from_u64(42);
289
-
290
- // All delays with full jitter should be between 0 and base_delay_ms
291
- for attempt in 1..=5 {
292
- let delay = policy.calculate_delay_with_rng(attempt, 1.0, &mut rng);
293
- assert!(delay <= 100);
294
- }
295
- }
296
-
297
- #[test]
298
- fn test_jitter_factor() {
299
- let policy = Policy {
300
- max_attempts: 5,
301
- base_delay_ms: 1000,
302
- multiplier: 1.0,
303
- max_delay_ms: 10_000,
304
- };
305
-
306
- let mut rng = StdRng::seed_from_u64(42);
307
-
308
- // 10% jitter: delay should be between 900ms (90%) and 1000ms (100%)
309
- let delay = policy.calculate_delay_with_rng(1, 0.1, &mut rng);
310
- assert!(
311
- delay >= 900 && delay <= 1000,
312
- "delay {} not in range 900-1000",
313
- delay
314
- );
315
-
316
- // No jitter: delay should be exactly base_delay_ms
317
- let delay = policy.calculate_delay_with_rng(1, 0.0, &mut rng);
318
- assert_eq!(delay, 1000);
319
-
320
- // Full jitter: delay should be between 0 and 1000ms
321
- let delay = policy.calculate_delay_with_rng(1, 1.0, &mut rng);
322
- assert!(delay <= 1000);
323
- }
324
-
325
- #[test]
326
- fn test_jitter_factor_clamping() {
327
- let policy = Policy {
328
- max_attempts: 5,
329
- base_delay_ms: 1000,
330
- multiplier: 1.0,
331
- max_delay_ms: 10_000,
332
- };
333
-
334
- let mut rng = StdRng::seed_from_u64(42);
335
-
336
- // Negative jitter_factor should be clamped to 0.0
337
- let delay = policy.calculate_delay_with_rng(1, -0.5, &mut rng);
338
- assert_eq!(delay, 1000, "negative jitter_factor should clamp to 0.0");
339
-
340
- // jitter_factor > 1.0 should be clamped to 1.0
341
- let delay = policy.calculate_delay_with_rng(1, 2.0, &mut rng);
342
- assert!(
343
- delay <= 1000,
344
- "jitter_factor > 1.0 should clamp to 1.0, got delay {}",
345
- delay
346
- );
347
-
348
- // Extreme values should still be clamped
349
- let delay = policy.calculate_delay_with_rng(1, 999.0, &mut rng);
350
- assert!(delay <= 1000, "extreme jitter_factor should be clamped");
351
-
352
- let delay = policy.calculate_delay_with_rng(1, -999.0, &mut rng);
353
- assert_eq!(delay, 1000, "extreme negative should clamp to 0.0");
354
- }
355
- }
242
+ mod tests;