From a6153325cad46d2138f412f8db0ad05f4ca6ff89 Mon Sep 17 00:00:00 2001 From: David Jonas Date: Sat, 28 Mar 2026 23:27:16 -0700 Subject: [PATCH 1/2] Revert "Add Pool::spawn_background_tasks() for more explicit multi-runtime support" This reverts commit 1fe2adb65e60757368f74fdb239691287034444a. --- src/conn/pool/mod.rs | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/src/conn/pool/mod.rs b/src/conn/pool/mod.rs index 198d541..d5fd061 100644 --- a/src/conn/pool/mod.rs +++ b/src/conn/pool/mod.rs @@ -121,12 +121,6 @@ pub struct Inner { /// /// Note that you will probably want to await [`Pool::disconnect`] before dropping the runtime, as /// otherwise you may end up with a number of connections that are not cleanly terminated. -/// -/// ## Multi-runtime environments -/// -/// In multi-runtime environments such as actix-web, the pool's background tasks must -/// be explicitly started on the long-lived root runtime before worker runtimes begin -/// using the pool. See [`Pool::spawn_background_tasks`] for details. #[derive(Debug, Clone)] pub struct Pool { opts: Opts, @@ -169,38 +163,6 @@ impl Pool { } } - /// Explicitly spawns the pool's background tasks on the current Tokio runtime. - /// - /// In most applications this method is unnecessary — the background tasks are spawned - /// automatically on the first call to [`Pool::get_conn`]. - /// - /// # When to use this - /// - /// In multi-runtime environments (e.g., [actix-web](https://actix.rs/)), the lazy - /// spawning may cause the background tasks to be bound to a short-lived worker runtime - /// rather than the application's long-lived root runtime. When that worker runtime shuts - /// down, the [`Recycler`] is dropped, setting the pool's close flag and causing all - /// subsequent [`Pool::get_conn`] calls to return [`DriverError::PoolDisconnected`]. - /// - /// Call this method once during startup, from within the long-lived runtime, before any - /// worker runtimes call [`Pool::get_conn`]. - /// - /// **This method must be called from within the Tokio runtime that should own the - /// background tasks.** - /// - /// # Idempotency - /// - /// This method is a no-op after the first successful call. - /// - /// # Panics - /// - /// Panics if called outside of a Tokio runtime context. - pub fn spawn_background_tasks(&self) { - let mut exchange = self.inner.exchange.lock().unwrap(); - - exchange.spawn_futures_if_needed(&self.inner); - } - /// Returns metrics for the connection pool. pub fn metrics(&self) -> Arc { self.inner.metrics.clone() From aff473f171584bb1dffc1ad2224dc2e79987ae51 Mon Sep 17 00:00:00 2001 From: David Jonas Date: Sat, 28 Mar 2026 23:33:35 -0700 Subject: [PATCH 2/2] Adds warning to Pool docs about multi-runtime environments --- src/conn/pool/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/conn/pool/mod.rs b/src/conn/pool/mod.rs index d5fd061..7b1450f 100644 --- a/src/conn/pool/mod.rs +++ b/src/conn/pool/mod.rs @@ -121,6 +121,19 @@ pub struct Inner { /// /// Note that you will probably want to await [`Pool::disconnect`] before dropping the runtime, as /// otherwise you may end up with a number of connections that are not cleanly terminated. +/// +/// ## Multi-runtime environments +/// +/// `Pool` must not be shared across independent tokio runtimes. Each `tokio::net::TcpStream` +/// inside a pooled connection is bound to the I/O driver of the runtime that established it; +/// connections become invalid when that runtime shuts down. This is most likely to surface +/// during graceful shutdown, when some runtimes exit before others while pooled connections +/// are still in circulation. The pool's background tasks ([`Recycler`], TTL interval) are +/// also spawned on the first runtime to call [`Pool::get_conn`] and do not survive that +/// runtime's shutdown. +/// +/// If your framework runs each worker on its own `current_thread` runtime (e.g. actix-server), +/// create a separate `Pool` per worker rather than sharing one across all workers. #[derive(Debug, Clone)] pub struct Pool { opts: Opts,