ntex_util/services/
inflight.rs1use ntex_service::{Ctx, Middleware, Service};
3
4use super::counter::Counter;
5
6#[derive(Copy, Clone, Debug)]
11pub struct InFlight {
12 max_inflight: usize,
13}
14
15impl InFlight {
16 pub fn new(max: usize) -> Self {
17 Self { max_inflight: max }
18 }
19}
20
21impl Default for InFlight {
22 fn default() -> Self {
23 Self::new(15)
24 }
25}
26
27impl<S, St> Middleware<S, St> for InFlight {
28 type Service = InFlightService<S>;
29
30 fn create(&self, _: &St, service: S) -> Self::Service {
31 InFlightService {
32 service,
33 count: Counter::new(self.max_inflight),
34 }
35 }
36}
37
38#[derive(Debug)]
39pub struct InFlightService<S> {
40 count: Counter,
41 service: S,
42}
43
44impl<S> InFlightService<S> {
45 pub fn new(max: usize, service: S) -> Self {
46 Self {
47 service,
48 count: Counter::new(max),
49 }
50 }
51}
52
53impl<S, St, Req> Service<St, Req> for InFlightService<S>
54where
55 S: Service<St, Req>,
56{
57 type Res = S::Res;
58 type Error = S::Error;
59
60 #[inline]
61 async fn ready(&self, ctx: Ctx<'_, Self, St>) -> Result<(), S::Error> {
62 if self.count.is_available() {
63 ctx.ready(&self.service).await
64 } else {
65 crate::future::join(self.count.available(), ctx.ready(&self.service))
66 .await
67 .1
68 }
69 }
70
71 #[inline]
72 async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<S::Res, S::Error> {
73 ctx.ready(self).await?;
74 let _guard = self.count.get();
75 ctx.call(&self.service, req).await
76 }
77
78 ntex_service::forward_shutdown!(St, service);
79}
80
81#[cfg(test)]
82mod tests {
83 use std::{cell::Cell, cell::RefCell, rc::Rc, task::Poll, time::Duration};
84
85 use async_channel as mpmc;
86 use ntex_service::{Pipeline, apply, fn_factory};
87
88 use super::*;
89 use crate::{channel::oneshot, future::lazy};
90
91 struct SleepService(mpmc::Receiver<()>);
92
93 impl Service<(), ()> for SleepService {
94 type Res = ();
95 type Error = ();
96
97 async fn call(&self, _r: (), _: Ctx<'_, Self>) -> Result<(), ()> {
98 let _ = self.0.recv().await;
99 Ok(())
100 }
101 }
102
103 #[ntex::test]
104 async fn test_service() {
105 let (tx, rx) = mpmc::unbounded();
106 let counter = Rc::new(Cell::new(0));
107
108 let srv = Pipeline::new((), InFlightService::new(1, SleepService(rx)));
109 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
110
111 let counter2 = counter.clone();
112 let fut = srv.call_nowait(());
113 ntex::rt::spawn(async move {
114 let _ = fut.await;
115 counter2.set(counter2.get() + 1);
116 });
117 crate::time::sleep(Duration::from_millis(25)).await;
118 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
119
120 let counter2 = counter.clone();
121 let fut = srv.call_nowait(());
122 ntex::rt::spawn(async move {
123 let _ = fut.await;
124 counter2.set(counter2.get() + 1);
125 });
126 crate::time::sleep(Duration::from_millis(25)).await;
127 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
128
129 let counter2 = counter.clone();
130 let fut = srv.call_static(());
131 let (stx, srx) = oneshot::channel::<()>();
132 ntex::rt::spawn(async move {
133 let _ = fut.await;
134 counter2.set(counter2.get() + 1);
135 let _ = stx.send(());
136 });
137 crate::time::sleep(Duration::from_millis(25)).await;
138 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
139
140 let _ = tx.send(()).await;
141 crate::time::sleep(Duration::from_millis(25)).await;
142 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
143
144 let _ = tx.send(()).await;
145 crate::time::sleep(Duration::from_millis(25)).await;
146 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
147
148 let _ = tx.send(()).await;
149 let _ = srx.recv().await;
150 assert_eq!(counter.get(), 3);
151 srv.shutdown().await;
152 }
153
154 #[ntex::test]
155 async fn test_middleware() {
156 assert_eq!(InFlight::default().max_inflight, 15);
157 assert_eq!(
158 format!("{:?}", InFlight::new(1)),
159 "InFlight { max_inflight: 1 }"
160 );
161
162 let (tx, rx) = mpmc::unbounded();
163 let rx = RefCell::new(Some(rx));
164 let sf = apply(
165 InFlight::new(1),
166 fn_factory(move |(): &()| {
167 let rx = rx.borrow_mut().take().unwrap();
168 async move { Ok::<_, ()>(SleepService(rx)) }
169 }),
170 );
171
172 let srv = sf.pipeline(()).await.unwrap();
173 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
174
175 let srv2 = srv.bind();
176 ntex::rt::spawn(async move {
177 let _ = srv2.call(()).await;
178 });
179 crate::time::sleep(Duration::from_millis(25)).await;
180 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
181
182 let _ = tx.send(()).await;
183 crate::time::sleep(Duration::from_millis(25)).await;
184 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
185 }
186
187 #[ntex::test]
188 async fn test_middleware2() {
189 assert_eq!(InFlight::default().max_inflight, 15);
190 assert_eq!(
191 format!("{:?}", InFlight::new(1)),
192 "InFlight { max_inflight: 1 }"
193 );
194
195 let (tx, rx) = mpmc::unbounded();
196 let rx = RefCell::new(Some(rx));
197 let sf = apply(
198 InFlight::new(1),
199 fn_factory(move |(): &()| {
200 let rx = rx.borrow_mut().take().unwrap();
201 async move { Ok::<_, ()>(SleepService(rx)) }
202 }),
203 );
204
205 let srv = sf.pipeline(()).await.unwrap();
206 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
207
208 let srv2 = srv.bind();
209 ntex::rt::spawn(async move {
210 let _ = srv2.call(()).await;
211 });
212 crate::time::sleep(Duration::from_millis(25)).await;
213 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
214
215 let _ = tx.send(()).await;
216 crate::time::sleep(Duration::from_millis(25)).await;
217 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
218 }
219}