mirror of
https://github.com/ntex-rs/ntex.git
synced 2025-04-03 21:07:39 +03:00
Added Service::poll() method (#481)
This commit is contained in:
parent
80d20e4371
commit
e33149df1b
42 changed files with 229 additions and 391 deletions
|
@ -1,5 +1,9 @@
|
|||
# Changes
|
||||
|
||||
## [2.8.0] - 2024-12-04
|
||||
|
||||
* Use updated Service trait
|
||||
|
||||
## [2.7.0] - 2024-12-03
|
||||
|
||||
* Add time::Sleep::elapse() method
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ntex-util"
|
||||
version = "2.7.0"
|
||||
version = "2.8.0"
|
||||
authors = ["ntex contributors <team@ntex.rs>"]
|
||||
description = "Utilities for ntex framework"
|
||||
keywords = ["network", "framework", "async", "futures"]
|
||||
|
@ -16,7 +16,7 @@ name = "ntex_util"
|
|||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
ntex-service = "3.3"
|
||||
ntex-service = "3.4"
|
||||
ntex-rt = "0.4"
|
||||
bitflags = "2"
|
||||
fxhash = "0.2"
|
||||
|
|
|
@ -70,7 +70,6 @@ where
|
|||
fn create(&self, service: S) -> Self::Service {
|
||||
BufferService {
|
||||
service: Pipeline::new(service).bind(),
|
||||
service_pending: Cell::new(true),
|
||||
size: self.buf_size,
|
||||
ready: Cell::new(false),
|
||||
buf: RefCell::new(VecDeque::with_capacity(self.buf_size)),
|
||||
|
@ -113,7 +112,6 @@ impl<E: std::fmt::Display + std::fmt::Debug> std::error::Error for BufferService
|
|||
pub struct BufferService<R, S: Service<R>> {
|
||||
size: usize,
|
||||
ready: Cell<bool>,
|
||||
service_pending: Cell<bool>,
|
||||
service: PipelineBinding<S, R>,
|
||||
buf: RefCell<VecDeque<oneshot::Sender<oneshot::Sender<()>>>>,
|
||||
next_call: RefCell<Option<oneshot::Receiver<()>>>,
|
||||
|
@ -131,7 +129,6 @@ where
|
|||
Self {
|
||||
size,
|
||||
service: Pipeline::new(service).bind(),
|
||||
service_pending: Cell::new(true),
|
||||
ready: Cell::new(false),
|
||||
buf: RefCell::new(VecDeque::with_capacity(size)),
|
||||
next_call: RefCell::default(),
|
||||
|
@ -158,7 +155,6 @@ where
|
|||
size: self.size,
|
||||
ready: Cell::new(false),
|
||||
service: self.service.clone(),
|
||||
service_pending: Cell::new(false),
|
||||
buf: RefCell::new(VecDeque::with_capacity(self.size)),
|
||||
next_call: RefCell::default(),
|
||||
cancel_on_shutdown: self.cancel_on_shutdown,
|
||||
|
@ -178,7 +174,6 @@ where
|
|||
.field("cancel_on_shutdown", &self.cancel_on_shutdown)
|
||||
.field("ready", &self.ready)
|
||||
.field("service", &self.service)
|
||||
.field("service_pending", &self.service_pending)
|
||||
.field("buf", &self.buf)
|
||||
.field("next_call", &self.next_call)
|
||||
.finish()
|
||||
|
@ -208,18 +203,14 @@ where
|
|||
if buffer.len() < self.size {
|
||||
// buffer next request
|
||||
self.ready.set(false);
|
||||
self.service_pending.set(false);
|
||||
Poll::Ready(Ok(()))
|
||||
} else {
|
||||
log::trace!("Buffer limit exceeded");
|
||||
// service is not ready
|
||||
self.service_pending.set(true);
|
||||
let _ = self.readiness.take().map(|w| w.wake());
|
||||
Poll::Pending
|
||||
}
|
||||
} else {
|
||||
self.service_pending.set(false);
|
||||
|
||||
while let Some(sender) = buffer.pop_front() {
|
||||
let (next_call_tx, next_call_rx) = oneshot::channel();
|
||||
if sender.send(next_call_tx).is_err()
|
||||
|
@ -240,19 +231,6 @@ where
|
|||
.await
|
||||
}
|
||||
|
||||
async fn not_ready(&self) {
|
||||
let fut = poll_fn(|cx| {
|
||||
if self.service_pending.get() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
self.readiness.set(Some(cx.waker().clone()));
|
||||
Poll::Pending
|
||||
}
|
||||
});
|
||||
|
||||
crate::future::select(fut, self.service.get_ref().not_ready()).await;
|
||||
}
|
||||
|
||||
async fn shutdown(&self) {
|
||||
// hold advancement until the last released task either makes a call or is dropped
|
||||
let next_call = self.next_call.borrow_mut().take();
|
||||
|
@ -318,6 +296,8 @@ where
|
|||
Ok(self.service.call(req).await?)
|
||||
}
|
||||
}
|
||||
|
||||
ntex_service::forward_poll!(service);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -373,7 +353,6 @@ mod tests {
|
|||
let srv =
|
||||
Pipeline::new(BufferService::new(2, TestService(inner.clone())).clone()).bind();
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Pending);
|
||||
|
||||
let srv1 = srv.clone();
|
||||
ntex::rt::spawn(async move {
|
||||
|
@ -382,7 +361,6 @@ mod tests {
|
|||
crate::time::sleep(Duration::from_millis(25)).await;
|
||||
assert_eq!(inner.count.get(), 0);
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Pending);
|
||||
|
||||
let srv1 = srv.clone();
|
||||
ntex::rt::spawn(async move {
|
||||
|
@ -391,12 +369,10 @@ mod tests {
|
|||
crate::time::sleep(Duration::from_millis(25)).await;
|
||||
assert_eq!(inner.count.get(), 0);
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Ready(()));
|
||||
|
||||
inner.ready.set(true);
|
||||
inner.waker.wake();
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Pending);
|
||||
|
||||
crate::time::sleep(Duration::from_millis(25)).await;
|
||||
assert_eq!(inner.count.get(), 1);
|
||||
|
@ -404,7 +380,6 @@ mod tests {
|
|||
inner.ready.set(true);
|
||||
inner.waker.wake();
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Pending);
|
||||
|
||||
crate::time::sleep(Duration::from_millis(25)).await;
|
||||
assert_eq!(inner.count.get(), 2);
|
||||
|
@ -417,12 +392,10 @@ mod tests {
|
|||
|
||||
let srv = Pipeline::new(BufferService::new(2, TestService(inner.clone()))).bind();
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Pending);
|
||||
|
||||
let _ = srv.call(()).await;
|
||||
assert_eq!(inner.count.get(), 1);
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Pending);
|
||||
assert!(lazy(|cx| srv.poll_shutdown(cx)).await.is_ready());
|
||||
|
||||
let err = BufferServiceError::from("test");
|
||||
|
|
|
@ -71,13 +71,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn not_ready(&self) {
|
||||
if self.count.is_available() {
|
||||
crate::future::select(self.count.unavailable(), self.service.not_ready()).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn call(
|
||||
&self,
|
||||
|
@ -88,6 +81,7 @@ where
|
|||
ctx.call(&self.service, req).await
|
||||
}
|
||||
|
||||
ntex_service::forward_poll!(service);
|
||||
ntex_service::forward_shutdown!(service);
|
||||
}
|
||||
|
||||
|
@ -118,7 +112,6 @@ mod tests {
|
|||
|
||||
let srv = Pipeline::new(InFlightService::new(1, SleepService(rx))).bind();
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Pending);
|
||||
|
||||
let srv2 = srv.clone();
|
||||
ntex::rt::spawn(async move {
|
||||
|
@ -126,12 +119,10 @@ mod tests {
|
|||
});
|
||||
crate::time::sleep(Duration::from_millis(25)).await;
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Ready(()));
|
||||
|
||||
let _ = tx.send(());
|
||||
crate::time::sleep(Duration::from_millis(25)).await;
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Pending);
|
||||
srv.shutdown().await;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{cell::Cell, convert::Infallible, fmt, marker, time};
|
||||
use std::{cell::Cell, convert::Infallible, fmt, marker, task::Context, task::Poll, time};
|
||||
|
||||
use ntex_service::{Service, ServiceCtx, ServiceFactory};
|
||||
|
||||
|
@ -119,22 +119,26 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
async fn not_ready(&self) {
|
||||
loop {
|
||||
self.sleep.wait().await;
|
||||
|
||||
let now = now();
|
||||
let expire = self.expire.get() + time::Duration::from(self.dur);
|
||||
if expire <= now {
|
||||
return;
|
||||
} else {
|
||||
let expire = expire - now;
|
||||
self.sleep
|
||||
.reset(Millis(expire.as_millis().try_into().unwrap_or(u32::MAX)));
|
||||
fn poll(&self, cx: &mut Context<'_>) -> Result<(), Self::Error> {
|
||||
match self.sleep.poll_elapsed(cx) {
|
||||
Poll::Ready(_) => {
|
||||
let now = now();
|
||||
let expire = self.expire.get() + time::Duration::from(self.dur);
|
||||
if expire <= now {
|
||||
Err((self.f)())
|
||||
} else {
|
||||
let expire = expire - now;
|
||||
self.sleep
|
||||
.reset(Millis(expire.as_millis().try_into().unwrap_or(u32::MAX)));
|
||||
let _ = self.sleep.poll_elapsed(cx);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Poll::Pending => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn call(&self, req: R, _: ServiceCtx<'_, Self>) -> Result<R, E> {
|
||||
self.expire.set(now());
|
||||
Ok(req)
|
||||
|
@ -162,13 +166,11 @@ mod tests {
|
|||
|
||||
assert_eq!(service.call(1usize).await, Ok(1usize));
|
||||
assert!(lazy(|cx| service.poll_ready(cx)).await.is_ready());
|
||||
assert!(!lazy(|cx| service.poll_not_ready(cx)).await.is_ready());
|
||||
|
||||
sleep(Millis(500)).await;
|
||||
assert_eq!(
|
||||
lazy(|cx| service.poll_ready(cx)).await,
|
||||
Poll::Ready(Err(TestErr))
|
||||
);
|
||||
assert!(lazy(|cx| service.poll_not_ready(cx)).await.is_ready());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,24 +65,6 @@ where
|
|||
ctx.ready(&self.service).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn not_ready(&self) {
|
||||
if self.ready.get() {
|
||||
crate::future::select(
|
||||
poll_fn(|cx| {
|
||||
self.waker.register(cx.waker());
|
||||
if self.ready.get() {
|
||||
Poll::Pending
|
||||
} else {
|
||||
Poll::Ready(())
|
||||
}
|
||||
}),
|
||||
self.service.not_ready(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn call(
|
||||
&self,
|
||||
|
@ -90,7 +72,6 @@ where
|
|||
ctx: ServiceCtx<'_, Self>,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
self.ready.set(false);
|
||||
self.waker.wake();
|
||||
|
||||
let result = ctx.call(&self.service, req).await;
|
||||
self.ready.set(true);
|
||||
|
@ -98,6 +79,7 @@ where
|
|||
result
|
||||
}
|
||||
|
||||
ntex_service::forward_poll!(service);
|
||||
ntex_service::forward_shutdown!(service);
|
||||
}
|
||||
|
||||
|
@ -127,7 +109,6 @@ mod tests {
|
|||
|
||||
let srv = Pipeline::new(OneRequestService::new(SleepService(rx))).bind();
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Pending);
|
||||
|
||||
let srv2 = srv.clone();
|
||||
ntex::rt::spawn(async move {
|
||||
|
@ -135,12 +116,10 @@ mod tests {
|
|||
});
|
||||
crate::time::sleep(Duration::from_millis(25)).await;
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Pending);
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Ready(()));
|
||||
|
||||
let _ = tx.send(());
|
||||
crate::time::sleep(Duration::from_millis(25)).await;
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
assert_eq!(lazy(|cx| srv.poll_not_ready(cx)).await, Poll::Pending);
|
||||
srv.shutdown().await;
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
ntex_service::forward_poll!(service, TimeoutError::Service);
|
||||
ntex_service::forward_ready!(service, TimeoutError::Service);
|
||||
ntex_service::forward_shutdown!(service);
|
||||
}
|
||||
|
|
|
@ -143,23 +143,10 @@ macro_rules! variant_impl ({$mod_name:ident, $enum_type:ident, $srv_type:ident,
|
|||
}).await
|
||||
}
|
||||
|
||||
async fn not_ready(&self) {
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
let mut fut1 = ::std::pin::pin!(self.V1.not_ready());
|
||||
$(let mut $T = ::std::pin::pin!(self.$T.not_ready());)+
|
||||
|
||||
::std::future::poll_fn(|cx| {
|
||||
if Pin::new(&mut fut1).poll(cx).is_ready() {
|
||||
return Poll::Ready(())
|
||||
}
|
||||
|
||||
$(if Pin::new(&mut $T).poll(cx).is_ready() {
|
||||
return Poll::Ready(());
|
||||
})+
|
||||
|
||||
Poll::Pending
|
||||
}).await
|
||||
fn poll(&self, cx: &mut std::task::Context<'_>) -> Result<(), Self::Error> {
|
||||
self.V1.poll(cx)?;
|
||||
$(self.$T.poll(cx)?;)+
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn shutdown(&self) {
|
||||
|
@ -253,7 +240,6 @@ variant_impl_and!(VariantFactory7, VariantFactory8, V8, V8R, v8, (V2, V3, V4, V5
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ntex_service::fn_factory;
|
||||
use std::{future::poll_fn, future::Future, pin};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -307,16 +293,7 @@ mod tests {
|
|||
let service = factory.pipeline(&()).await.unwrap().clone();
|
||||
assert!(format!("{:?}", service).contains("Variant"));
|
||||
|
||||
let mut f = pin::pin!(service.not_ready());
|
||||
let _ = poll_fn(|cx| {
|
||||
if pin::Pin::new(&mut f).poll(cx).is_pending() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
assert!(crate::future::lazy(|cx| service.poll(cx)).await.is_ok());
|
||||
assert!(service.ready().await.is_ok());
|
||||
service.shutdown().await;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue