use crate::AuthResult;
use std::{future::Future, pin::Pin};
pub type BackgroundTaskCompletion = Pin<Box<dyn Future<Output = AuthResult<()>> + Send + 'static>>;
pub trait BackgroundTaskHandler: Send + Sync {
fn handle(&self, completion: BackgroundTaskCompletion) -> AuthResult<()>;
}
pub async fn start_background_task(
operation: impl Future<Output = AuthResult<()>> + Send + 'static,
) -> AuthResult<BackgroundTaskCompletion> {
use tracing::{Instrument, instrument::WithSubscriber};
let request_context = crate::hooks::current_request_hook_context();
let work = crate::hooks::with_optional_request_hook_context(request_context, operation)
.instrument(tracing::Span::current())
.with_current_subscriber();
let mut work: BackgroundTaskCompletion = Box::pin(work);
match std::future::poll_fn(|context| std::task::Poll::Ready(work.as_mut().poll(context))).await
{
std::task::Poll::Ready(result) => Ok(Box::pin(async move { result })),
std::task::Poll::Pending => {
let executor = tokio::runtime::Handle::try_current().map_err(|error| {
crate::AuthError::internal(format!(
"Background task requires a Tokio executor: {error}"
))
})?;
let running = executor.spawn(work);
Ok(Box::pin(async move {
running.await.map_err(|error| {
crate::AuthError::internal(format!("Background task failed: {error}"))
})?
}))
}
}
}