From 63792327776ade657bdd4c73f5aa8d0d6f88e4ad Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Sat, 2 Dec 2023 14:34:53 +0100 Subject: [PATCH 1/2] Gracefully handle accept errors in `serve` --- axum/CHANGELOG.md | 2 ++ axum/src/macros.rs | 12 ++++++++++++ axum/src/serve.rs | 36 +++++++++++++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md index 4012f6034d..bf7321766a 100644 --- a/axum/CHANGELOG.md +++ b/axum/CHANGELOG.md @@ -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) diff --git a/axum/src/macros.rs b/axum/src/macros.rs index 180c3c05a5..7024f77998 100644 --- a/axum/src/macros.rs +++ b/axum/src/macros.rs @@ -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)*) => {}; +} diff --git a/axum/src/serve.rs b/axum/src/serve.rs index c6aa2784c8..4e9c1d17da 100644 --- a/axum/src/serve.rs +++ b/axum/src/serve.rs @@ -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, From f5d36ad606bbda1adc4c13dbe93cd5b538c4f522 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Sat, 2 Dec 2023 19:00:53 +0100 Subject: [PATCH 2/2] Update axum/src/serve.rs Co-authored-by: Jonas Platte --- axum/src/serve.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/axum/src/serve.rs b/axum/src/serve.rs index 4e9c1d17da..f9b48c41e2 100644 --- a/axum/src/serve.rs +++ b/axum/src/serve.rs @@ -168,7 +168,7 @@ where // > and then the listener will sleep for 1 second. // // hyper allowed customizing this but axum does not. - error!("accept error: {}", e); + error!("accept error: {e}"); tokio::time::sleep(Duration::from_secs(1)).await; continue; }