apalis_core/worker/ext/parallelize/
mod.rs1use std::future::ready;
30
31use futures_core::future::BoxFuture;
32use futures_util::FutureExt;
33use futures_util::TryFutureExt;
34use tower_layer::{Layer, Stack};
35use tower_service::Service;
36
37use crate::{backend::Backend, error::BoxDynError, task::Task, worker::builder::WorkerBuilder};
38
39pub trait ParallelizeExt<Args, Source, Middleware, Executor>: Sized {
41 fn parallelize(
43 self,
44 f: Executor,
45 ) -> WorkerBuilder<Args, Source, Stack<ParallelizeLayer<Executor>, Middleware>>;
46}
47
48#[derive(Debug, Clone, Default)]
50pub struct ParallelizeLayer<Executor> {
51 executor: Executor,
52}
53
54impl<Executor> ParallelizeLayer<Executor> {
55 pub fn new(executor: Executor) -> Self {
57 Self { executor }
58 }
59}
60
61impl<S, Executor: Clone> Layer<S> for ParallelizeLayer<Executor> {
62 type Service = ParallelizeService<S, Executor>;
63
64 fn layer(&self, service: S) -> Self::Service {
65 ParallelizeService {
66 service,
67 executor: self.executor.clone(),
68 }
69 }
70}
71
72#[derive(Debug, Clone)]
74pub struct ParallelizeService<S, Executor> {
75 service: S,
76 executor: Executor,
77}
78
79impl<S, Args, Fut, T, Executor, ExecErr> Service<Task<Args>> for ParallelizeService<S, Executor>
80where
81 S: Service<Task<Args>, Future = Fut>,
82 Executor: Fn(Fut) -> T + Send + 'static,
83 Fut: Future<Output = Result<S::Response, S::Error>> + Send + 'static,
84 T: Future<Output = Result<Result<S::Response, S::Error>, ExecErr>> + Send + 'static,
85 S::Error: Into<BoxDynError> + Send + 'static,
86 ExecErr: Into<BoxDynError>,
87 S::Response: Send + 'static,
88{
89 type Response = S::Response;
90 type Error = BoxDynError;
91 type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
92
93 fn poll_ready(
94 &mut self,
95 cx: &mut std::task::Context<'_>,
96 ) -> std::task::Poll<Result<(), Self::Error>> {
97 self.service.poll_ready(cx).map_err(|e| e.into())
98 }
99
100 fn call(&mut self, request: Task<Args>) -> Self::Future {
101 (self.executor)(self.service.call(request))
102 .map_err(|e| e.into())
103 .and_then(|s| ready(s.map_err(|e| e.into())))
104 .boxed()
105 }
106}
107
108impl<Args, P, M, Executor> ParallelizeExt<Args, P, M, Executor> for WorkerBuilder<Args, P, M>
109where
110 P: Backend,
111 M: Layer<ParallelizeLayer<Executor>>,
112{
113 fn parallelize(
114 self,
115 f: Executor,
116 ) -> WorkerBuilder<Args, P, Stack<ParallelizeLayer<Executor>, M>> {
117 self.layer(ParallelizeLayer::new(f))
118 }
119}