1#![allow(clippy::type_complexity)]
3use std::cell::{Cell, RefCell};
4use std::task::Poll;
5use std::{collections::VecDeque, fmt, future, future::Future, marker, mem, pin, rc::Rc};
6
7use ntex_service::{BindCtx, Ctx, Middleware, ReadyNotifier, Service, pipeline::PipelineState};
8
9use crate::{channel::oneshot, future::OnDropFn, task::LocalWaker};
10
11#[derive(Copy, Clone, Debug)]
12pub struct Buffer<St: Clone, Req, Res, Err> {
18 buf_size: usize,
19 cancel_on_shutdown: bool,
20 st: marker::PhantomData<fn(St, Req) -> Result<Res, Err>>,
21}
22
23impl<St: Clone, Req, Res, Err> Buffer<St, Req, Res, Err> {
24 #[must_use]
28 pub fn buf_size(mut self, size: usize) -> Self {
29 self.buf_size = size;
30 self
31 }
32
33 #[must_use]
37 pub fn cancel_on_shutdown(mut self) -> Self {
38 self.cancel_on_shutdown = true;
39 self
40 }
41}
42
43impl<St: Clone, Req, Res, Err> Default for Buffer<St, Req, Res, Err> {
44 fn default() -> Self {
45 Self {
46 buf_size: 16,
47 cancel_on_shutdown: false,
48 st: marker::PhantomData,
49 }
50 }
51}
52
53impl<S, St, Req, Res, Err> Middleware<S, St> for Buffer<St, Req, Res, Err>
54where
55 S: Service<St, Req, Res = Res, Error = Err> + 'static,
56 St: Clone + 'static,
57 Req: 'static,
58 Res: 'static,
59 Err: 'static,
60{
61 type Service = BufferService<St, Req, Res, Err>;
62
63 fn create(&self, _: &St, service: S) -> Self::Service {
64 let service = BufferService::new(self.buf_size, PipelineState::new(service));
65 if self.cancel_on_shutdown {
66 service.cancel_on_shutdown()
67 } else {
68 service
69 }
70 }
71}
72
73#[derive(Clone, Copy, Debug, PartialEq, Eq)]
75pub enum BufferServiceError<E> {
76 Service(E),
78 RequestCanceled,
80}
81
82impl<E> From<E> for BufferServiceError<E> {
83 fn from(err: E) -> Self {
84 BufferServiceError::Service(err)
85 }
86}
87
88impl<E: fmt::Display> fmt::Display for BufferServiceError<E> {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 match self {
91 BufferServiceError::Service(e) => fmt::Display::fmt(e, f),
92 BufferServiceError::RequestCanceled => f.write_str("buffer service request canceled"),
93 }
94 }
95}
96
97impl<E: fmt::Display + fmt::Debug> std::error::Error for BufferServiceError<E> {}
98
99pub struct BufferService<St, Req, Res, Err> {
121 shared: Rc<Shared>,
122 service: PipelineState<St, Req, Res, Err>,
123 cancel_on_shutdown: bool,
124}
125
126struct Shared {
127 size: usize,
128 buf: RefCell<VecDeque<oneshot::Sender<Token>>>,
129 has_token: Cell<bool>,
131 in_flight: Cell<usize>,
133 canceled: Cell<bool>,
134 notifier: ReadyNotifier,
135 token_waker: LocalWaker,
136 drained: LocalWaker,
137}
138
139impl Shared {
140 fn has_room(&self) -> bool {
141 self.buf.borrow().len() < self.size
142 }
143
144 fn is_drained(&self) -> bool {
145 !self.has_token.get() && self.in_flight.get() == 0 && self.buf.borrow().is_empty()
146 }
147
148 fn release_next(self: &Rc<Self>) {
150 loop {
151 let (sender, freed) = {
152 let mut buf = self.buf.borrow_mut();
153 let full = buf.len() >= self.size;
154 let sender = buf.pop_front();
155 (sender, full && buf.len() < self.size)
156 };
157 let Some(sender) = sender else {
158 self.has_token.set(false);
159 self.drained.wake();
160 return;
161 };
162 let token = Token(Some(self.clone()));
163 if freed {
164 self.notifier.notify();
165 }
166 match sender.send(token) {
167 Ok(()) => return,
168 Err(token) => token.disarm(),
170 }
171 }
172 }
173
174 fn prune(&self) {
176 let freed = {
177 let mut buf = self.buf.borrow_mut();
178 let full = buf.len() >= self.size;
179 buf.retain(|sender| !sender.is_canceled());
180 full && buf.len() < self.size
181 };
182 if freed {
183 self.notifier.notify();
184 }
185 }
186}
187
188struct Token(Option<Rc<Shared>>);
190
191impl Token {
192 fn disarm(mut self) {
193 self.0 = None;
194 }
195}
196
197impl Drop for Token {
198 fn drop(&mut self) {
199 if let Some(shared) = self.0.take() {
200 shared.release_next();
201 }
202 }
203}
204
205struct Waiter<'a> {
207 shared: &'a Shared,
208 rx: Option<oneshot::Receiver<Token>>,
209}
210
211impl Drop for Waiter<'_> {
212 fn drop(&mut self) {
213 if let Some(rx) = self.rx.take() {
214 drop(rx);
216 self.shared.prune();
217 }
218 }
219}
220
221struct InFlight<'a>(&'a Shared);
222
223impl Drop for InFlight<'_> {
224 fn drop(&mut self) {
225 self.0.in_flight.set(self.0.in_flight.get() - 1);
226 self.0.drained.wake();
227 }
228}
229
230impl<St, Req, Res, Err> BufferService<St, Req, Res, Err>
231where
232 St: Clone + 'static,
233{
234 #[must_use]
235 pub fn new(size: usize, service: PipelineState<St, Req, Res, Err>) -> Self {
237 let size = size.max(1);
238 Self {
239 shared: Rc::new(Shared {
240 size,
241 buf: RefCell::new(VecDeque::with_capacity(size)),
242 has_token: Cell::new(false),
243 in_flight: Cell::new(0),
244 canceled: Cell::new(false),
245 notifier: ReadyNotifier::new(),
246 token_waker: LocalWaker::new(),
247 drained: LocalWaker::new(),
248 }),
249 service,
250 cancel_on_shutdown: false,
251 }
252 }
253
254 #[must_use]
255 pub fn cancel_on_shutdown(self) -> Self {
257 Self {
258 cancel_on_shutdown: true,
259 ..self
260 }
261 }
262}
263
264impl<St, Req, Res, Err> fmt::Debug for BufferService<St, Req, Res, Err> {
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 f.debug_struct("BufferService")
267 .field("size", &self.shared.size)
268 .field("cancel_on_shutdown", &self.cancel_on_shutdown)
269 .field("buffered", &self.shared.buf.borrow().len())
270 .field("in_flight", &self.shared.in_flight.get())
271 .field("service", &self.service)
272 .finish()
273 }
274}
275
276impl<St, Req, Res, Err> Service<St, Req> for BufferService<St, Req, Res, Err>
277where
278 St: Clone + 'static,
279 Req: 'static,
280 Res: 'static,
281 Err: 'static,
282{
283 type Res = Res;
284 type Error = BufferServiceError<Err>;
285
286 fn bind(&self, ctx: BindCtx<'_>) {
287 ctx.subscribe(&self.shared.notifier);
289 }
290
291 async fn ready(&self, _: Ctx<'_, Self, St>) -> Result<(), Self::Error> {
292 if self.shared.has_room() {
293 Ok(())
294 } else {
295 log::trace!("Buffer limit exceeded");
296 future::pending().await
298 }
299 }
300
301 async fn shutdown(&self, ctx: Ctx<'_, Self, St>) {
302 let shared = &self.shared;
303 if self.cancel_on_shutdown {
304 shared.canceled.set(true);
305 let buf = mem::take(&mut *shared.buf.borrow_mut());
306 let freed = buf.len() >= shared.size;
307 let _cancel = OnDropFn::new(|| {
308 shared.token_waker.wake();
309 drop(buf);
311 });
312 if freed {
313 shared.notifier.notify();
314 }
315 }
316
317 future::poll_fn(|cx| {
318 if shared.is_drained() {
319 return Poll::Ready(());
320 }
321 shared.drained.register(cx.waker());
322 if shared.is_drained() {
323 Poll::Ready(())
324 } else {
325 Poll::Pending
326 }
327 })
328 .await;
329
330 self.service.shutdown(ctx.st()).await;
331 }
332
333 async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<Res, Self::Error> {
334 let shared = &self.shared;
335 let idle = !shared.has_token.get() && shared.buf.borrow().is_empty();
336 if idle && self.service.is_ready() {
337 return Ok(self.service.call(req, ctx.st()).await?);
338 }
339
340 let (token, mut buffered) = if idle {
341 shared.has_token.set(true);
342 (Token(Some(shared.clone())), false)
343 } else {
344 let (tx, rx) = oneshot::channel();
345 let full = {
346 let mut buf = shared.buf.borrow_mut();
347 buf.push_back(tx);
348 buf.len() == shared.size
349 };
350 let mut waiter = Waiter {
351 shared,
352 rx: Some(rx),
353 };
354 if full {
355 shared.notifier.notify();
356 }
357 let result = future::poll_fn(|cx| waiter.rx.as_ref().unwrap().poll_recv(cx)).await;
358 waiter.rx = None;
359 let token = result.map_err(|_| {
360 log::trace!("Buffered service request canceled");
361 BufferServiceError::RequestCanceled
362 })?;
363 (token, true)
364 };
365
366 let mut ready = pin::pin!(self.service.ready(ctx.st()));
368 future::poll_fn(|cx| {
369 if shared.canceled.get() {
370 return Poll::Ready(Err(BufferServiceError::RequestCanceled));
371 }
372 if let Poll::Ready(result) = ready.as_mut().poll(cx) {
373 Poll::Ready(result.map_err(BufferServiceError::Service))
374 } else {
375 buffered = true;
376 shared.token_waker.register(cx.waker());
377 Poll::Pending
378 }
379 })
380 .await?;
381
382 let _in_flight = buffered.then(|| {
383 shared.in_flight.set(shared.in_flight.get() + 1);
384 InFlight(shared)
385 });
386 drop(token);
387
388 Ok(self.service.call(req, ctx.st()).await?)
389 }
390}
391
392#[cfg(test)]
393mod tests {
394 #![allow(clippy::unused_async_trait_impl)]
395 use ntex_service::{Pipeline, ReadyCallback, apply, fn_factory};
396 use std::{cell::RefCell, pin::Pin, time::Duration};
397 use std::{panic::AssertUnwindSafe, panic::catch_unwind, task::Context};
398
399 use super::*;
400 use crate::future::lazy;
401
402 #[derive(Debug, Clone)]
403 struct TestService(Rc<Inner>);
404
405 #[derive(Debug, Default)]
406 struct Inner {
407 ready: Cell<bool>,
408 waker: LocalWaker,
409 changed: ReadyNotifier,
410 count: Cell<usize>,
411 }
412
413 impl Inner {
414 fn new(ready: bool) -> Rc<Self> {
415 let inner = Rc::new(Self::default());
416 inner.ready.set(ready);
417 inner
418 }
419
420 fn set_ready(&self) {
421 self.ready.set(true);
422 self.waker.wake();
423 }
424 }
425
426 impl Service<(), ()> for TestService {
427 type Res = ();
428 type Error = ();
429
430 fn bind(&self, ctx: BindCtx<'_>) {
431 ctx.subscribe(&self.0.changed);
432 }
433
434 async fn ready(&self, _: Ctx<'_, Self, ()>) -> Result<(), Self::Error> {
435 future::poll_fn(|cx| {
436 self.0.waker.register(cx.waker());
437 if self.0.ready.get() {
438 Poll::Ready(Ok(()))
439 } else {
440 Poll::Pending
441 }
442 })
443 .await
444 }
445
446 async fn call(&self, _r: (), _: Ctx<'_, Self, ()>) -> Result<(), ()> {
447 self.0.ready.set(false);
449 self.0.changed.notify();
450 self.0.count.set(self.0.count.get() + 1);
451 Ok(())
452 }
453 }
454
455 fn spawn_call(
456 srv: &Pipeline<(), (), BufferServiceError<()>>,
457 ) -> Rc<RefCell<Option<Result<(), BufferServiceError<()>>>>> {
458 let result = Rc::new(RefCell::new(None));
459 let result2 = result.clone();
460 let srv = srv.bind();
461 ntex::rt::spawn(async move {
462 *result2.borrow_mut() = Some(srv.call(()).await);
463 });
464 result
465 }
466
467 async fn settle() {
468 crate::time::sleep(Duration::from_millis(25)).await;
469 }
470
471 #[ntex::test]
472 async fn test_service() {
473 let inner = Inner::new(false);
474 let svc = BufferService::new(2, PipelineState::new(TestService(inner.clone())));
475 assert!(format!("{svc:?}").contains("BufferService"));
476
477 let srv = Pipeline::new((), svc);
478 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
479
480 let _r1 = spawn_call(&srv);
482 let _r2 = spawn_call(&srv);
483 settle().await;
484 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
485 let _r3 = spawn_call(&srv);
486 settle().await;
487 assert_eq!(inner.count.get(), 0);
488 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
489
490 inner.set_ready();
492 settle().await;
493 assert_eq!(inner.count.get(), 1);
494 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
495
496 inner.set_ready();
497 settle().await;
498 assert_eq!(inner.count.get(), 2);
499
500 inner.set_ready();
501 settle().await;
502 assert_eq!(inner.count.get(), 3);
503 assert!(lazy(|cx| srv.poll_shutdown(cx)).await.is_ready());
504
505 let err = BufferServiceError::from("test");
506 assert!(format!("{err}").contains("test"));
507 assert!(format!("{:?}", Buffer::<(), (), (), ()>::default()).contains("Buffer"));
508 }
509
510 #[ntex::test]
511 async fn sequential_calls_with_ready_service() {
512 let inner = Rc::new(PendingInner::default());
513 let srv = Pipeline::new(
514 (),
515 BufferService::new(2, PipelineState::new(ReadyService(inner.clone()))),
516 );
517
518 for _ in 0..3 {
519 crate::time::timeout(Duration::from_secs(1), srv.call(()))
520 .await
521 .unwrap()
522 .unwrap();
523 }
524 assert_eq!(inner.count.get(), 3);
525 }
526
527 #[ntex::test]
528 #[allow(clippy::redundant_clone)]
529 async fn test_middleware() {
530 let inner = Inner::new(false);
531 let inner2 = inner.clone();
532
533 let srv = apply(
534 Buffer::default().buf_size(1),
535 fn_factory(async move |(): &()| Ok::<_, ()>(TestService(inner2.clone()))),
536 );
537
538 let srv = srv.pipeline(()).await.unwrap();
539 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
540
541 let srv1 = srv.bind();
542 ntex::rt::spawn(async move {
543 let _ = srv1.call(()).await;
544 });
545 let srv1 = srv.bind();
546 ntex::rt::spawn(async move {
547 let _ = srv1.call(()).await;
548 });
549 settle().await;
550 assert_eq!(inner.count.get(), 0);
551 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
552
553 inner.set_ready();
554 settle().await;
555 assert_eq!(inner.count.get(), 1);
556 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
557
558 inner.set_ready();
559 settle().await;
560 assert_eq!(inner.count.get(), 2);
561 }
562
563 #[ntex::test]
564 async fn middleware_cancels_buffered_requests_on_shutdown() {
565 let inner = Inner::new(false);
566 let inner2 = inner.clone();
567
568 let srv = apply(
569 Buffer::default().buf_size(1).cancel_on_shutdown(),
570 fn_factory(async move |(): &()| Ok::<_, ()>(TestService(inner2.clone()))),
571 )
572 .pipeline(())
573 .await
574 .unwrap();
575 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
576
577 let r1 = spawn_call(&srv);
579 let r2 = spawn_call(&srv);
580 settle().await;
581 crate::time::timeout(Duration::from_secs(1), srv.shutdown())
582 .await
583 .unwrap();
584 settle().await;
585
586 assert!(matches!(
587 *r1.borrow(),
588 Some(Err(BufferServiceError::RequestCanceled))
589 ));
590 assert!(matches!(
591 *r2.borrow(),
592 Some(Err(BufferServiceError::RequestCanceled))
593 ));
594 assert_eq!(inner.count.get(), 0);
595 }
596
597 #[derive(Default)]
598 struct PendingInner {
599 started: Cell<bool>,
600 completed: Cell<bool>,
601 shutdown: Cell<bool>,
602 count: Cell<usize>,
603 }
604
605 struct ReadyService(Rc<PendingInner>);
606
607 impl Service<(), ()> for ReadyService {
608 type Res = ();
609 type Error = ();
610
611 async fn call(&self, (): (), _: Ctx<'_, Self, ()>) -> Result<(), ()> {
612 self.0.count.set(self.0.count.get() + 1);
613 Ok(())
614 }
615 }
616
617 struct PendingService {
618 inner: Rc<PendingInner>,
619 release: RefCell<Option<oneshot::Receiver<()>>>,
620 }
621
622 impl Service<(), ()> for PendingService {
623 type Res = ();
624 type Error = ();
625
626 async fn call(&self, (): (), _: Ctx<'_, Self, ()>) -> Result<(), ()> {
627 self.inner.started.set(true);
628 let release = self.release.borrow_mut().take().unwrap();
629 release.recv().await.unwrap();
630 self.inner.completed.set(true);
631 Ok(())
632 }
633
634 async fn shutdown(&self, _: Ctx<'_, Self, ()>) {
635 self.inner.shutdown.set(true);
636 }
637 }
638
639 #[ntex::test]
640 async fn shutdown_with_in_flight_request() {
641 let inner = Rc::new(PendingInner::default());
642 let (release_tx, release_rx) = oneshot::channel();
643 let service = PendingService {
644 inner: inner.clone(),
645 release: RefCell::new(Some(release_rx)),
646 };
647 let srv = Pipeline::new((), BufferService::new(1, PipelineState::new(service)));
648
649 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
650
651 let srv2 = srv.bind();
652 ntex::rt::spawn(async move {
653 srv2.call(()).await.unwrap();
654 });
655 settle().await;
656
657 assert!(inner.started.get());
659 assert!(!inner.completed.get());
660 assert!(lazy(|cx| srv.poll_shutdown(cx)).await.is_ready());
661 assert!(inner.shutdown.get());
662 assert!(!inner.completed.get());
663
664 release_tx.send(()).unwrap();
665 settle().await;
666
667 assert!(inner.completed.get());
668 }
669
670 #[derive(Default)]
671 struct DrainInner {
672 ready: Cell<bool>,
673 waker: LocalWaker,
674 active: Cell<usize>,
675 count: Cell<usize>,
676 active_on_shutdown: Cell<Option<usize>>,
677 }
678
679 struct DrainService(Rc<DrainInner>);
680
681 impl Service<(), ()> for DrainService {
682 type Res = ();
683 type Error = ();
684
685 async fn ready(&self, _: Ctx<'_, Self, ()>) -> Result<(), ()> {
686 future::poll_fn(|cx| {
687 self.0.waker.register(cx.waker());
688 if self.0.ready.get() {
689 Poll::Ready(Ok(()))
690 } else {
691 Poll::Pending
692 }
693 })
694 .await
695 }
696
697 async fn call(&self, (): (), _: Ctx<'_, Self, ()>) -> Result<(), ()> {
698 let inner = &self.0;
699 inner.active.set(inner.active.get() + 1);
700 crate::time::sleep(Duration::from_millis(25)).await;
701 inner.active.set(inner.active.get() - 1);
702 inner.count.set(inner.count.get() + 1);
703 Ok(())
704 }
705
706 async fn shutdown(&self, _: Ctx<'_, Self, ()>) {
707 self.0.active_on_shutdown.set(Some(self.0.active.get()));
708 }
709 }
710
711 #[ntex::test]
712 async fn shutdown_drains_buffer() {
713 let inner = Rc::new(DrainInner::default());
714 let srv = Pipeline::new(
715 (),
716 BufferService::new(4, PipelineState::new(DrainService(inner.clone()))),
717 );
718
719 for _ in 0..2 {
720 srv.ready().await.unwrap();
721 let srv = srv.bind();
722 ntex::rt::spawn(async move {
723 srv.call(()).await.unwrap();
724 });
725 }
726 crate::time::sleep(Duration::from_millis(10)).await;
727 assert_eq!(inner.count.get(), 0);
728
729 inner.ready.set(true);
730 inner.waker.wake();
731 srv.shutdown().await;
732
733 assert_eq!(inner.count.get(), 2);
734 assert_eq!(inner.active_on_shutdown.get(), Some(0));
735 }
736
737 #[test]
738 fn request_canceled_display() {
739 let err = BufferServiceError::<&str>::RequestCanceled;
740 assert_eq!(err.to_string(), "buffer service request canceled");
741 }
742
743 #[ntex::test]
744 async fn dropped_requests_are_skipped() {
745 let inner = Inner::new(false);
746 let srv = Pipeline::new(
747 (),
748 BufferService::new(1, PipelineState::new(TestService(inner.clone()))),
749 );
750 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
751
752 let mut fut1 = srv.call_static(());
754 assert!(lazy(|cx| Pin::new(&mut fut1).poll(cx)).await.is_pending());
755 let mut fut2 = srv.call_static(());
756 assert!(lazy(|cx| Pin::new(&mut fut2).poll(cx)).await.is_pending());
757 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
758
759 drop(fut2);
761 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
762 let r3 = spawn_call(&srv);
763 settle().await;
764
765 drop(fut1);
767 inner.set_ready();
768 settle().await;
769 assert!(matches!(*r3.borrow(), Some(Ok(()))));
770 assert_eq!(inner.count.get(), 1);
771
772 let mut fut4 = srv.call_static(());
774 assert!(lazy(|cx| Pin::new(&mut fut4).poll(cx)).await.is_pending());
775 let mut fut5 = srv.call_static(());
776 assert!(lazy(|cx| Pin::new(&mut fut5).poll(cx)).await.is_pending());
777 drop(fut4);
778 drop(fut5);
779 inner.set_ready();
780 crate::time::timeout(Duration::from_secs(1), srv.call(()))
781 .await
782 .unwrap()
783 .unwrap();
784 assert_eq!(inner.count.get(), 2);
785 crate::time::timeout(Duration::from_secs(1), srv.shutdown())
786 .await
787 .unwrap();
788 }
789
790 #[ntex::test]
791 async fn shutdown_skips_dropped_buffered_request() {
792 let inner = Inner::new(false);
793 let srv = Pipeline::new(
794 (),
795 BufferService::new(2, PipelineState::new(TestService(inner.clone()))),
796 );
797 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
798
799 let mut fut1 = srv.call_static(());
800 assert!(lazy(|cx| Pin::new(&mut fut1).poll(cx)).await.is_pending());
801 let mut fut2 = srv.call_static(());
802 assert!(lazy(|cx| Pin::new(&mut fut2).poll(cx)).await.is_pending());
803 drop(fut2);
804 drop(fut1);
805
806 crate::time::timeout(Duration::from_secs(1), srv.shutdown())
807 .await
808 .unwrap();
809 assert_eq!(inner.count.get(), 0);
810 }
811
812 #[derive(Default)]
813 struct FailInner {
814 fail: Cell<bool>,
815 changed: ReadyNotifier,
816 }
817
818 struct FailService(Rc<FailInner>);
819
820 impl Service<(), ()> for FailService {
821 type Res = ();
822 type Error = ();
823
824 fn bind(&self, ctx: BindCtx<'_>) {
825 ctx.subscribe(&self.0.changed);
826 }
827
828 async fn ready(&self, _: Ctx<'_, Self, ()>) -> Result<(), ()> {
829 if self.0.fail.get() {
830 Err(())
831 } else {
832 future::pending().await
833 }
834 }
835
836 async fn call(&self, (): (), _: Ctx<'_, Self, ()>) -> Result<(), ()> {
837 unreachable!("FailService is never ready")
838 }
839 }
840
841 #[ntex::test]
842 async fn inner_ready_error_is_returned_to_requests() {
843 let inner = Rc::new(FailInner::default());
844 let srv = Pipeline::new(
845 (),
846 BufferService::new(2, PipelineState::new(FailService(inner.clone()))),
847 );
848 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
849
850 let r1 = spawn_call(&srv);
851 let r2 = spawn_call(&srv);
852 settle().await;
853 assert!(r1.borrow().is_none());
854
855 inner.fail.set(true);
856 inner.changed.notify();
857 crate::time::timeout(Duration::from_secs(1), srv.shutdown())
858 .await
859 .unwrap();
860 settle().await;
861
862 assert!(matches!(
863 *r1.borrow(),
864 Some(Err(BufferServiceError::Service(())))
865 ));
866 assert!(matches!(
867 *r2.borrow(),
868 Some(Err(BufferServiceError::Service(())))
869 ));
870 }
871
872 #[ntex::test]
873 async fn shared_buffer_capacity_notifies_all_roots() {
874 let inner = Inner::new(false);
875 let buffer = Rc::new(BufferService::new(
876 1,
877 PipelineState::new(TestService(inner.clone())),
878 ));
879 let first = Pipeline::new((), buffer.clone());
880 let second = Pipeline::new((), buffer);
881 first.ready().await.unwrap();
882 second.ready().await.unwrap();
883 let mut cx = Context::from_waker(std::task::Waker::noop());
884
885 let mut active = Box::pin(first.call(()));
886 assert!(active.as_mut().poll(&mut cx).is_pending());
887 let mut queued = Box::pin(second.call(()));
888 assert!(queued.as_mut().poll(&mut cx).is_pending());
889 assert!(first.poll_ready(&mut cx).is_pending());
890 assert!(second.poll_ready(&mut cx).is_pending());
891
892 drop(queued);
893 assert_eq!(first.poll_ready(&mut cx), Poll::Ready(Ok(())));
894 assert_eq!(second.poll_ready(&mut cx), Poll::Ready(Ok(())));
895 inner.set_ready();
896 assert_eq!(active.as_mut().poll(&mut cx), Poll::Ready(Ok(())));
897 }
898
899 #[ntex::test]
900 async fn notification_panics_do_not_strand_buffered_requests() {
901 let inner = Inner::new(false);
902 let buffer = Rc::new(BufferService::new(
903 1,
904 PipelineState::new(TestService(inner.clone())),
905 ));
906 let srv = Pipeline::new((), buffer.clone());
907 let panic_once = Rc::new(Cell::new(false));
908 let flag = panic_once.clone();
909 srv.on_notify(&ReadyCallback::new(move || {
910 assert!(!flag.replace(false), "notification panic");
911 }));
912 let mut cx = Context::from_waker(std::task::Waker::noop());
913 let mut active = Box::pin(srv.call(()));
914 assert!(active.as_mut().poll(&mut cx).is_pending());
915
916 panic_once.set(true);
917 let mut queued = Box::pin(srv.call(()));
918 assert!(catch_unwind(AssertUnwindSafe(|| queued.as_mut().poll(&mut cx))).is_err());
919 drop(queued);
920 assert!(buffer.shared.buf.borrow().is_empty());
921 assert_eq!(srv.poll_ready(&mut cx), Poll::Ready(Ok(())));
922
923 let mut queued = Box::pin(srv.call(()));
924 assert!(queued.as_mut().poll(&mut cx).is_pending());
925 panic_once.set(true);
926 assert!(catch_unwind(AssertUnwindSafe(|| drop(active))).is_err());
927 assert_eq!(
928 queued.as_mut().poll(&mut cx),
929 Poll::Ready(Err(BufferServiceError::RequestCanceled))
930 );
931 assert!(buffer.shared.is_drained());
932
933 inner.set_ready();
934 assert_eq!(srv.call(()).await, Ok(()));
935 }
936
937 #[ntex::test]
938 async fn shutdown_notification_panic_still_cancels_waiters() {
939 let inner = Inner::new(false);
940 let buffer = Rc::new(
941 BufferService::new(1, PipelineState::new(TestService(inner))).cancel_on_shutdown(),
942 );
943 let srv = Pipeline::new((), buffer.clone());
944 let mut cx = Context::from_waker(std::task::Waker::noop());
945 let mut active = Box::pin(srv.call(()));
946 assert!(active.as_mut().poll(&mut cx).is_pending());
947 let mut queued = Box::pin(srv.call(()));
948 assert!(queued.as_mut().poll(&mut cx).is_pending());
949 srv.on_notify(&ReadyCallback::new(|| panic!("shutdown notification")));
950
951 assert!(catch_unwind(AssertUnwindSafe(|| srv.poll_shutdown(&mut cx))).is_err());
952 assert_eq!(
953 active.as_mut().poll(&mut cx),
954 Poll::Ready(Err(BufferServiceError::RequestCanceled))
955 );
956 assert_eq!(
957 queued.as_mut().poll(&mut cx),
958 Poll::Ready(Err(BufferServiceError::RequestCanceled))
959 );
960 assert!(buffer.shared.is_drained());
961 }
962}