use std::time::Duration;
use tokio::time::sleep;
pub async fn delay_before<F, Fut, T>(delay: Duration, operation: F) -> T
where
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = T>,
{
sleep(delay).await;
operation().await
}
pub async fn ignore_error<F, Fut, T, E>(operation: F, context: &str) -> Option<T>
where
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = Result<T, E>>,
E: std::fmt::Display,
{
match operation().await {
Ok(value) => Some(value),
Err(e) => {
tracing::debug!("{}: {}", context, e);
None
}
}
}
pub async fn collect_results<F, Fut, T, E>(operations: Vec<F>, context: &str) -> Vec<Option<T>>
where
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = Result<T, E>>,
E: std::fmt::Display,
{
let mut results = Vec::new();
for (i, op) in operations.into_iter().enumerate() {
let ctx = format!("{context} (operation {i})");
results.push(ignore_error(op, &ctx).await);
}
results
}
pub async fn with_timeout_opt<F, Fut, T>(
operation: F,
timeout_duration: Duration,
context: &str,
) -> Option<T>
where
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = T>,
{
use tokio::time::timeout as tokio_timeout;
match tokio_timeout(timeout_duration, operation()).await {
Ok(value) => Some(value),
Err(_) => {
tracing::warn!(
"{}: Operation timed out after {:?}",
context,
timeout_duration
);
None
}
}
}