mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-07 00:00:15 +02:00
Gracefully handle accept errors in serve (#2400)
Co-authored-by: Jonas Platte <[email protected]>
This commit is contained in:
co-authored by
Jonas Platte
parent
6491655a80
commit
ef5663674c
@@ -8,8 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
# Unreleased
|
||||
|
||||
- **added:** Add `axum::body::to_bytes` ([#2373])
|
||||
- **fixed:** Gracefully handle accept errors in `serve` ([#2400])
|
||||
|
||||
[#2373]: https://github.com/tokio-rs/axum/pull/2373
|
||||
[#2400]: https://github.com/tokio-rs/axum/pull/2400
|
||||
|
||||
# 0.7.1 (27. November, 2023)
|
||||
|
||||
|
||||
@@ -66,3 +66,15 @@ macro_rules! all_the_tuples {
|
||||
$name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], T16);
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
macro_rules! error {
|
||||
($($tt:tt)*) => {
|
||||
tracing::error!($($tt)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "tracing"))]
|
||||
macro_rules! error {
|
||||
($($tt:tt)*) => {};
|
||||
}
|
||||
|
||||
+35
-1
@@ -8,6 +8,7 @@ use std::{
|
||||
net::SocketAddr,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use axum_core::{body::Body, extract::Request, response::Response};
|
||||
@@ -147,7 +148,31 @@ where
|
||||
} = self;
|
||||
|
||||
loop {
|
||||
let (tcp_stream, remote_addr) = tcp_listener.accept().await?;
|
||||
let (tcp_stream, remote_addr) = match tcp_listener.accept().await {
|
||||
Ok(conn) => conn,
|
||||
Err(e) => {
|
||||
// Connection errors can be ignored directly, continue
|
||||
// by accepting the next request.
|
||||
if is_connection_error(&e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// [From `hyper::Server` in 0.14](https://github.com/hyperium/hyper/blob/v0.14.27/src/server/tcp.rs#L186)
|
||||
//
|
||||
// > A possible scenario is that the process has hit the max open files
|
||||
// > allowed, and so trying to accept a new connection will fail with
|
||||
// > `EMFILE`. In some cases, it's preferable to just wait for some time, if
|
||||
// > the application will likely close some files (or connections), and try
|
||||
// > to accept the connection again. If this option is `true`, the error
|
||||
// > will be logged at the `error` level, since it is still a big deal,
|
||||
// > and then the listener will sleep for 1 second.
|
||||
//
|
||||
// hyper allowed customizing this but axum does not.
|
||||
error!("accept error: {e}");
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let tcp_stream = TokioIo::new(tcp_stream);
|
||||
|
||||
poll_fn(|cx| make_service.poll_ready(cx))
|
||||
@@ -187,6 +212,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn is_connection_error(e: &io::Error) -> bool {
|
||||
matches!(
|
||||
e.kind(),
|
||||
io::ErrorKind::ConnectionRefused
|
||||
| io::ErrorKind::ConnectionAborted
|
||||
| io::ErrorKind::ConnectionReset
|
||||
)
|
||||
}
|
||||
|
||||
mod private {
|
||||
use std::{
|
||||
future::Future,
|
||||
|
||||
Reference in New Issue
Block a user