alibi_core/
background_tasks.rs1use crate::AuthResult;
3use std::{future::Future, pin::Pin};
4
5pub type BackgroundTaskCompletion = Pin<Box<dyn Future<Output = AuthResult<()>> + Send + 'static>>;
9
10pub trait BackgroundTaskHandler: Send + Sync {
15 fn handle(&self, completion: BackgroundTaskCompletion) -> AuthResult<()>;
19}
20
21pub async fn start_background_task(
27 operation: impl Future<Output = AuthResult<()>> + Send + 'static,
28) -> AuthResult<BackgroundTaskCompletion> {
29 use tracing::{Instrument, instrument::WithSubscriber};
30 let request_context = crate::hooks::current_request_hook_context();
31 let work = crate::hooks::with_optional_request_hook_context(request_context, operation)
32 .instrument(tracing::Span::current())
33 .with_current_subscriber();
34 let mut work: BackgroundTaskCompletion = Box::pin(work);
35 match std::future::poll_fn(|context| std::task::Poll::Ready(work.as_mut().poll(context))).await
36 {
37 std::task::Poll::Ready(result) => Ok(Box::pin(async move { result })),
38 std::task::Poll::Pending => {
39 let executor = tokio::runtime::Handle::try_current().map_err(|error| {
40 crate::AuthError::internal(format!(
41 "Background task requires a Tokio executor: {error}"
42 ))
43 })?;
44 let running = executor.spawn(work);
45 Ok(Box::pin(async move {
46 running.await.map_err(|error| {
47 crate::AuthError::internal(format!("Background task failed: {error}"))
48 })?
49 }))
50 }
51 }
52}