1use std::{
2 num::NonZeroU32,
3 sync::atomic::{AtomicBool, Ordering},
4 thread::sleep,
5 time::Duration,
6};
7
8use nix::sys::pthread::pthread_self;
9
10use crate::xorshift::Xorshift128plus;
11
12pub static DEBUG: AtomicBool = AtomicBool::new(false);
13
14pub fn retry<R, E>(f: impl Fn() -> Result<R, E>) -> R {
20 let mut tries_left: u32 = 200;
21 let mut random = None;
22 loop {
23 if let Ok(r) = f() {
24 return r;
25 }
26 tries_left -= 1;
27 if tries_left == 0 {
28 panic!("can't seem to get this to succeed")
29 }
30 if tries_left < 100 {
31 if random.is_none() {
32 let tid = pthread_self() as u64;
33 random = Some(Xorshift128plus::new(tid));
34 }
35 let r = random.as_mut().expect("initialized above").get();
36 sleep(Duration::from_micros(r & 16383));
37 if true || DEBUG.load(Ordering::Relaxed) {
38 eprintln!(
39 "note: retrying with {tries_left} tries left via `retry` at {}:{}",
40 file!(),
41 line!()
42 );
43 }
44 }
45 }
46}
47
48pub fn retry_n<R, E>(
51 max_tries: NonZeroU32,
52 sleep_ms: u64,
53 f: impl Fn() -> Result<R, E>,
54) -> Result<R, E> {
55 let mut tries_left: u32 = max_tries.into();
56 loop {
57 match f() {
58 Ok(r) => return Ok(r),
59 Err(e) => {
60 tries_left -= 1;
61 if tries_left == 0 {
62 return Err(e);
63 }
64 sleep(Duration::from_millis(sleep_ms));
65 }
66 }
67 if DEBUG.load(Ordering::Relaxed) {
68 eprintln!("note: retrying via `retry_n` at {}:{}", file!(), line!());
69 }
70 }
71}