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<()>;
20}
21
22pub async fn start_background_task(
28 operation: impl Future<Output = AuthResult<()>> + Send + 'static,
29) -> AuthResult<BackgroundTaskCompletion> {
30 use tracing::{Instrument, instrument::WithSubscriber};
31 let request_context = crate::hooks::current_request_hook_context();
32 let work = async move {
33 match request_context {
34 Some(context) => {
35 crate::hooks::with_request_hook_context_value(context, operation).await
36 }
37 None => operation.await,
38 }
39 }
40 .instrument(tracing::Span::current())
41 .with_current_subscriber();
42 let mut work: BackgroundTaskCompletion = Box::pin(work);
43 match std::future::poll_fn(|context| std::task::Poll::Ready(work.as_mut().poll(context))).await
44 {
45 std::task::Poll::Ready(result) => Ok(Box::pin(async move { result })),
46 std::task::Poll::Pending => {
47 let executor = tokio::runtime::Handle::try_current().map_err(|error| {
48 crate::AuthError::internal(format!(
49 "Background task requires a Tokio executor: {error}"
50 ))
51 })?;
52 let running = executor.spawn(work);
53 Ok(Box::pin(async move {
54 running.await.map_err(|error| {
55 crate::AuthError::internal(format!("Background task failed: {error}"))
56 })?
57 }))
58 }
59 }
60}