Skip to content

Commit 7c4afe6

Browse files
authored
fix: disable connection pooling to prevent stale connections after SnapStart (#671)
hyper-util's connection pool uses std::time::Instant (CLOCK_MONOTONIC) to track idle connection age. After Lambda SnapStart restore (or freeze/thaw cycles), CLOCK_MONOTONIC can be inconsistent, causing the pool to reuse dead connections and resulting in IncompleteMessage errors. This is a known upstream issue (hyperium/hyper#3810, rust-lang/rust#79462) with no fix planned in hyper-util or Rust stdlib. Disable connection pooling entirely via pool_max_idle_per_host(0). Since the adapter communicates with localhost, the overhead of creating a new TCP connection per request is negligible (microseconds). Closes #604
1 parent 028f205 commit 7c4afe6

1 file changed

Lines changed: 19 additions & 5 deletions

File tree

src/lib.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -520,8 +520,12 @@ impl Adapter<HttpConnector, Body> {
520520
/// Creates a new HTTP Adapter instance.
521521
///
522522
/// This function initializes a new HTTP client configured to communicate with
523-
/// your web application. The client uses connection pooling with a 4-second
524-
/// idle timeout for optimal Lambda performance.
523+
/// your web application. When Lambda SnapStart is detected
524+
/// (`AWS_LAMBDA_INITIALIZATION_TYPE=snap-start`), connection pooling is
525+
/// disabled to prevent stale connections after restore, where
526+
/// `CLOCK_MONOTONIC` inconsistencies can cause hyper's pool to reuse dead
527+
/// connections. Otherwise, a 4-second idle timeout is used for connection
528+
/// pooling.
525529
///
526530
/// # Arguments
527531
///
@@ -546,9 +550,19 @@ impl Adapter<HttpConnector, Body> {
546550
/// let adapter = Adapter::new(&options).expect("Failed to create adapter");
547551
/// ```
548552
pub fn new(options: &AdapterOptions) -> Result<Adapter<HttpConnector, Body>, Error> {
549-
let client = Client::builder(hyper_util::rt::TokioExecutor::new())
550-
.pool_idle_timeout(Duration::from_secs(4))
551-
.build(HttpConnector::new());
553+
let mut builder = Client::builder(hyper_util::rt::TokioExecutor::new());
554+
555+
// When running under SnapStart, CLOCK_MONOTONIC can be inconsistent after
556+
// restore, causing hyper's pool to reuse dead connections (hyper#3810,
557+
// rust-lang/rust#79462). Disable pooling in that case. For localhost
558+
// communication the overhead of new TCP connections is negligible.
559+
if env::var("AWS_LAMBDA_INITIALIZATION_TYPE").as_deref() == Ok("snap-start") {
560+
builder.pool_max_idle_per_host(0);
561+
} else {
562+
builder.pool_idle_timeout(Duration::from_secs(4));
563+
}
564+
565+
let client = builder.build(HttpConnector::new());
552566

553567
let schema = "http";
554568

0 commit comments

Comments
 (0)