首页 > 解决方案 > 如何防止 BB8 连接在多次重复后断开

问题描述

我有一个应用程序应该为所有请求使用共享连接池。我观察到,在看似随机的时间,请求失败,错误类型为“已关闭”。我已将此行为隔离到以下示例中:

use lazy_static::lazy_static;

use bb8_postgres::bb8::Pool;
use bb8_postgres::PostgresConnectionManager;
use bb8_postgres::tokio_postgres::{NoTls, Client};

lazy_static! {
    static ref CONNECTION_POOL: Pool<PostgresConnectionManager<NoTls>> = {
        let manager = PostgresConnectionManager::new_from_stringlike("dbname=demodb host=localhost user=postgres", NoTls).unwrap();

        Pool::builder().build_unchecked(manager)
    };
}

fn main() {
    println!("Hello, world!");
}


#[cfg(test)]
mod test {
    use super::*;

    #[tokio::test]
    async fn much_insert_traffic() {
        much_traffic("INSERT INTO foo(a,b) VALUES (1, 2) RETURNING id").await
    }

    #[tokio::test]
    async fn much_select_traffic() {
        much_traffic("SELECT MAX(id) FROM foo").await
    }

    #[tokio::test]
    async fn much_update_traffic() {
        much_traffic("UPDATE foo SET a = 81 WHERE id = 1919 RETURNING b").await;
    }

    async fn much_traffic(stmt: &str) {
        let c = CONNECTION_POOL.get().await.expect("Get a connection");
        let client = &*c;

        for i in 0..10000i32 {
            let res = client.query_opt(stmt, &[]).await.expect(&format!("Perform repeat {} of {} ok", i, stmt));
        }
    }

}

执行测试时,>50% 的测试将在以后的迭代中失败,输出类似于以下内容:

执行 UPDATE foo SET a = 81 WHERE id = 1919 RETURNING b ok 的重复 8782:错误 { 种类:已关闭,原因:无 } 线程“test::much_update_traffic”在“执行 UPDATE foo SET a = 81 WHERE id 的重复 8782 时惊慌失措” = 1919 返回 b ok:错误 { 种类:已关闭,原因:无 }',src\main.rs:44:23

标签: postgresqlrustrust-tokio

解决方案


事实证明,问题完全取决于[tokio::test]注释在执行测试时启动不同的运行时。惰性静态使用这些运行时之一进行初始化,并且一旦该运行时关闭,池就会被销毁。只要生成测试仍在运行,其他测试(具有不同的运行时)就可以使用该值,但是一旦它关闭就会遇到无效状态。


推荐阅读