Use async fn for Service::ready() and Service::shutdown() (#363)

This commit is contained in:
Nikolay Kim 2024-05-28 16:55:08 +05:00 committed by GitHub
parent dec6ab083a
commit b04bdf41f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 285 additions and 299 deletions

View file

@ -1,5 +1,9 @@
# Changes
## [2.0.0] - 2024-05-28
* Use async fn for Service::ready() and Service::shutdown()
## [1.0.5] - 2024-04-02
* Fix external configuration handling

View file

@ -1,6 +1,6 @@
[package]
name = "ntex-server"
version = "1.0.5"
version = "2.0.0"
authors = ["ntex contributors <team@ntex.rs>"]
description = "Server for ntex framework"
keywords = ["network", "framework", "async", "futures"]
@ -16,11 +16,11 @@ name = "ntex_server"
path = "src/lib.rs"
[dependencies]
ntex-bytes = "0.1.24"
ntex-net = "1.0"
ntex-service = "2.0"
ntex-rt = "0.4.13"
ntex-util = "1.0"
ntex-bytes = "0.1"
ntex-net = "2.0"
ntex-service = "3.0"
ntex-rt = "0.4"
ntex-util = "2.0"
async-channel = "2"
async-broadcast = "0.7"

View file

@ -1,4 +1,4 @@
use std::{cell::Cell, rc::Rc, task};
use std::{cell::Cell, future::poll_fn, rc::Rc, task, task::Poll};
use ntex_util::task::LocalWaker;
@ -30,8 +30,15 @@ impl Counter {
/// Check if counter is not at capacity. If counter at capacity
/// it registers notification for current task.
pub(super) fn available(&self, cx: &mut task::Context<'_>) -> bool {
self.0.available(cx)
pub(super) async fn available(&self) {
poll_fn(|cx| {
if self.0.available(cx) {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await
}
/// Get total number of acquired counts

View file

@ -1,4 +1,3 @@
use std::task::{Context, Poll};
use std::{fmt, future::Future, marker::PhantomData};
use ntex_bytes::PoolId;
@ -144,10 +143,10 @@ where
type Response = ();
type Error = ();
ntex_service::forward_poll_shutdown!(inner);
ntex_service::forward_shutdown!(inner);
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), ()>> {
self.inner.poll_ready(cx).map_err(|_| ())
async fn ready(&self, ctx: ServiceCtx<'_, Self>) -> Result<(), ()> {
ctx.ready(&self.inner).await.map_err(|_| ())
}
async fn call(&self, req: Io, ctx: ServiceCtx<'_, Self>) -> Result<(), ()> {

View file

@ -1,5 +1,3 @@
use std::{task::Context, task::Poll};
use ntex_bytes::{Pool, PoolRef};
use ntex_net::Io;
use ntex_service::{boxed, Service, ServiceCtx, ServiceFactory};
@ -142,53 +140,34 @@ impl Service<ServerMessage> for StreamServiceImpl {
type Response = ();
type Error = ();
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let mut ready = self.conns.available(cx);
async fn ready(&self, ctx: ServiceCtx<'_, Self>) -> Result<(), Self::Error> {
self.conns.available().await;
for (idx, svc) in self.services.iter().enumerate() {
match svc.poll_ready(cx) {
Poll::Pending => ready = false,
Poll::Ready(Ok(())) => (),
Poll::Ready(Err(_)) => {
match ctx.ready(svc).await {
Ok(()) => (),
Err(_) => {
for (idx_, tag, _, _) in self.tokens.values() {
if idx == *idx_ {
log::error!("{}: Service readiness has failed", tag);
break;
}
}
return Poll::Ready(Err(()));
return Err(());
}
}
}
// check memory pools
for (_, _, pool, _) in self.tokens.values() {
ready = pool.poll_ready(cx).is_ready() && ready;
}
if ready {
Poll::Ready(Ok(()))
} else {
Poll::Pending
}
Ok(())
}
fn poll_shutdown(&self, cx: &mut Context<'_>) -> Poll<()> {
let mut ready = true;
async fn shutdown(&self) {
for svc in &self.services {
match svc.poll_shutdown(cx) {
Poll::Pending => ready = false,
Poll::Ready(_) => (),
}
}
if ready {
log::info!(
"Worker service shutdown, {} connections",
super::num_connections()
);
Poll::Ready(())
} else {
Poll::Pending
svc.shutdown().await;
}
log::info!(
"Worker service shutdown, {} connections",
super::num_connections()
);
}
async fn call(&self, req: ServerMessage, ctx: ServiceCtx<'_, Self>) -> Result<(), ()> {

View file

@ -6,7 +6,7 @@ use async_broadcast::{self as bus, broadcast};
use async_channel::{unbounded, Receiver, Sender};
use ntex_rt::{spawn, Arbiter};
use ntex_service::{Pipeline, ServiceFactory};
use ntex_service::{Pipeline, PipelineBinding, ServiceFactory};
use ntex_util::future::{select, stream_recv, Either, Stream};
use ntex_util::time::{sleep, timeout_checked, Millis};
@ -240,8 +240,10 @@ struct WorkerSt<T, F: ServiceFactory<WorkerMessage<T>>> {
availability: WorkerAvailabilityTx,
}
async fn run_worker<T, F>(mut svc: Pipeline<F::Service>, mut wrk: WorkerSt<T, F>)
where
async fn run_worker<T, F>(
mut svc: PipelineBinding<F::Service, WorkerMessage<T>>,
mut wrk: WorkerSt<T, F>,
) where
T: Send + 'static,
F: ServiceFactory<WorkerMessage<T>> + 'static,
{
@ -250,7 +252,7 @@ where
ready!(svc.poll_ready(cx)?);
if let Some(item) = ready!(Pin::new(&mut wrk.rx).poll_next(cx)) {
let fut = svc.call_static(WorkerMessage::New(item));
let fut = svc.call(WorkerMessage::New(item));
let _ = spawn(async move {
let _ = fut.await;
});
@ -267,17 +269,17 @@ where
wrk.availability.set(false);
if timeout.is_zero() {
let fut = svc.call_static(WorkerMessage::ForceShutdown);
let fut = svc.call(WorkerMessage::ForceShutdown);
let _ = spawn(async move {
let _ = fut.await;
});
sleep(STOP_TIMEOUT).await;
} else {
let fut = svc.call_static(WorkerMessage::Shutdown(timeout));
let fut = svc.call(WorkerMessage::Shutdown(timeout));
let res = timeout_checked(timeout, fut).await;
let _ = result.send(res.is_ok());
};
poll_fn(|cx| svc.poll_shutdown(cx)).await;
svc.shutdown().await;
log::info!("Stopping worker {:?}", wrk.id);
return;
@ -289,7 +291,7 @@ where
match select(wrk.factory.create(()), stream_recv(&mut wrk.stop)).await {
Either::Left(Ok(service)) => {
wrk.availability.set(true);
svc = Pipeline::new(service);
svc = Pipeline::new(service).bind();
break;
}
Either::Left(Err(_)) => sleep(STOP_TIMEOUT).await,
@ -305,7 +307,13 @@ async fn create<T, F>(
stop: Receiver<Shutdown>,
factory: Result<F, ()>,
availability: WorkerAvailabilityTx,
) -> Result<(Pipeline<F::Service>, WorkerSt<T, F>), ()>
) -> Result<
(
PipelineBinding<F::Service, WorkerMessage<T>>,
WorkerSt<T, F>,
),
(),
>
where
T: Send + 'static,
F: ServiceFactory<WorkerMessage<T>> + 'static,
@ -317,7 +325,7 @@ where
let mut stop = Box::pin(stop);
let svc = match select(factory.create(()), stream_recv(&mut stop)).await {
Either::Left(Ok(svc)) => Pipeline::new(svc),
Either::Left(Ok(svc)) => Pipeline::new(svc).bind(),
Either::Left(Err(_)) => return Err(()),
Either::Right(Some(Shutdown { result, .. })) => {
log::trace!("Shutdown uninitialized worker");