use anyhow::Result;
use futures::stream::AbortHandle;
use futures::stream::Abortable;
use std::future::Future;
use tokio::task::JoinHandle;
use tokio::time::Duration;
pub fn spawn<F>(name: &'static str, f: F) -> std::thread::JoinHandle<()>
where
F: 'static + Send + FnOnce() -> Result<()>,
{
std::thread::Builder::new()
.name(name.to_owned())
.spawn(move || {
if let Err(e) = f() {
warn!("{} thread failed: {}", name, e);
}
})
.expect("failed to spawn a thread")
}
pub fn spawn_task<T, F>(name: &'static str, future: F) -> JoinHandle<()>
where
T: Send + 'static,
F: Future<Output = Result<T>> + Send + 'static,
{
tokio::task::spawn(async move {
if let Err(err) = future.await {
warn!("task '{}' failed: {}", name, err)
}
})
}
pub async fn run_with_timeout<F, T>(duration: Duration, future: F) -> Result<T>
where
F: std::future::Future<Output = T>,
{
let (abort_handle, abort_registration) = AbortHandle::new_pair();
let abortable_future = Abortable::new(future, abort_registration);
tokio::pin!(abortable_future);
tokio::select! {
result = &mut abortable_future => {
match result {
Ok(val) => Ok(val),
Err(e) => bail!(e.to_string())
}
}
_ = tokio::time::sleep(duration) => {
abort_handle.abort(); bail!("Timeout occurred after {} seconds", duration.as_secs())
}
}
}