use std::convert::Infallible;
use std::future::Future;
use std::time::Duration;
use rand::Rng;
use crate::Task;
pub struct Immortal(Task<Infallible>);
impl Immortal {
pub fn spawn<F: Future<Output = Infallible> + Send + 'static>(f: F) -> Self {
Self(crate::spawn(f))
}
pub fn respawn<T, F>(
strategy: RespawnStrategy,
mut inner: impl FnMut() -> F + Send + 'static,
) -> Self
where
T: Send + 'static,
F: Future<Output = T> + Send + 'static,
{
let task = crate::spawn(async move {
loop {
inner().await;
match strategy {
RespawnStrategy::Immediate => tokio::task::yield_now().await,
RespawnStrategy::FixedDelay(delay) => tokio::time::sleep(delay).await,
RespawnStrategy::JitterDelay(low, high) => {
let low = low.min(high);
let millis = rand::thread_rng()
.gen_range((low.as_millis() as u64)..=(high.as_millis() as u64));
tokio::time::sleep(Duration::from_millis(millis)).await;
}
}
}
});
Self(task)
}
pub async fn cancel(self) {
self.0.cancel().await;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RespawnStrategy {
Immediate,
FixedDelay(Duration),
JitterDelay(Duration, Duration),
}