Skip to content

Commit

Permalink
Gracefully handle accept errors in serve (#2400)
Browse files Browse the repository at this point in the history
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
  • Loading branch information
davidpdrsn and jplatte committed Dec 2, 2023
1 parent 6491655 commit ef56636
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 1 deletion.
2 changes: 2 additions & 0 deletions axum/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
12 changes: 12 additions & 0 deletions axum/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)*) => {};
}
36 changes: 35 additions & 1 deletion axum/src/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::{
net::SocketAddr,
pin::Pin,
task::{Context, Poll},
time::Duration,
};

use axum_core::{body::Body, extract::Request, response::Response};
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit ef56636

Please sign in to comment.