use std::{convert::Infallible, time::Duration};
use async_task::Task;
use futures_lite::Future;
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: Send, F: Future<Output = T> + Send>(
strategy: RespawnStrategy,
mut inner: impl FnMut() -> F + Send + 'static,
) -> Self {
let task = crate::spawn(async move {
loop {
inner().await;
match strategy {
RespawnStrategy::Immediate => futures_lite::future::yield_now().await,
RespawnStrategy::FixedDelay(delay) => {
async_io::Timer::after(delay).await;
}
RespawnStrategy::JitterDelay(low, high) => {
let low = low.min(high);
let delay = Duration::from_millis(fastrand::u64(
(low.as_millis() as u64)..=(high.as_millis() as u64),
));
async_io::Timer::after(delay).await;
}
}
}
});
Self(task)
}
pub async fn cancel(self) {
self.0.cancel().await;
}
}
pub enum RespawnStrategy {
Immediate,
FixedDelay(Duration),
JitterDelay(Duration, Duration),
}