use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
use std::time::Duration;
use taskvisor::prelude::*;
struct EndpointProbe {
endpoint: Arc<str>,
attempts: AtomicU32,
}
impl Task for EndpointProbe {
fn spawn(&self, ctx: TaskContext) -> BoxTaskFuture {
let endpoint = Arc::clone(&self.endpoint);
let attempt = self.attempts.fetch_add(1, Ordering::Relaxed) + 1;
Box::pin(async move {
println!("[probe] {endpoint}, attempt #{attempt}");
ctx.run_until_cancelled(tokio::time::sleep(Duration::from_millis(100)))
.await?;
if attempt == 1 {
Err(TaskError::fail("endpoint not ready"))
} else {
Ok(())
}
})
}
}
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let task: TaskRef = Arc::new(EndpointProbe {
endpoint: Arc::from("https://service.internal/health"),
attempts: AtomicU32::new(0),
});
let spec = TaskSpec::restartable("endpoint-probe", task)
.with_backoff(BackoffPolicy::constant(Duration::from_millis(100)));
let supervisor = Supervisor::new(SupervisorConfig::default(), vec![]);
supervisor.run(vec![spec]).await?;
Ok(())
}