Hi guys, I met one DB pool issue with SeaORM/LazyLock/tokio.
This is the demo code:
#[cfg(test)]
mod tests {
use std::sync::LazyLock;
use sea_orm::{ConnectionTrait, Database, DatabaseBackend, DatabaseConnection, Statement};
use tokio::runtime::Runtime;
use tracing::{debug, error, info};
// this will block
static DB_CONNECTION: LazyLock<DatabaseConnection> = LazyLock::new(|| {
dbg!("in db connecting");
let re = Runtime::new().unwrap().block_on(async {
Database::connect("postgres://test_user:test_password@localhost:5432/test_db")
.await
.expect("db connect error")
});
dbg!("connected");
re
});
#[test]
fn test() {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.with_test_writer()
.init();
LazyLock::force(&DB_CONNECTION);
let rt = Runtime::new().unwrap();
rt.block_on(async {
dbg!("in here?");
let re = DB_CONNECTION
.execute(Statement::from_string(
DatabaseBackend::Postgres,
"DELETE FROM test_table;",
))
.await
.unwrap();
dbg!(re);
dbg!("done");
})
}
}
Then I run env RUST_LOG="debug" cargo test
. The stdout is
---- tests::test stdout ----
[src/main.rs:15:9] "in db connecting" = "in db connecting"
[src/main.rs:21:9] "connected" = "connected"
[src/main.rs:55:13] "in here?" = "in here?"
2025-01-11T17:54:21.109897Z DEBUG sea_orm::driver::sqlx_postgres: DELETE FROM test_table;
thread 'tests::test' panicked at src/main.rs:62:18:
called `Result::unwrap()` on an `Err` value: ConnectionAcquire(Timeout)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
After some source code check, the debug log is here. I also check the acquire()
, it in sqlx
I run some code change try to get more details.
Rather than use the static, I create it inside test()
:
#[test]
fn test() {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.with_test_writer()
.init();
// this also timeout
let DB_CONNECTION: LazyLock<DatabaseConnection> = LazyLock::new(|| {
dbg!("in db connecting");
let re = Runtime::new().unwrap().block_on(async {
Database::connect("postgres://test_user:test_password@localhost:5432/test_db")
.await
.expect("db connect error")
});
dbg!("connected");
re
});
LazyLock::force(&DB_CONNECTION);
let rt = Runtime::new().unwrap();
rt.block_on(async {
dbg!("in here?");
let re = DB_CONNECTION
.execute(Statement::from_string(
DatabaseBackend::Postgres,
"DELETE FROM test_table;",
))
.await
.unwrap();
dbg!(re);
dbg!("done");
})
}
It still timeout, same issue as use static.
If I don't use the LazyLock:
let rt = Runtime::new().unwrap();
// code below is ok
let DB_CONNECTION = rt.block_on(async {
Database::connect("postgres://test_user:test_password@localhost:5432/test_db")
.await
.expect("db connect error")
});
rt.block_on(async {
dbg!("in here?");
let re = DB_CONNECTION
.execute(Statement::from_string(
DatabaseBackend::Postgres,
"DELETE FROM test_table;",
))
.await
.unwrap();
dbg!(re);
dbg!("done");
})
It works well.
I don't know which part causes this issue. Does anyone have some ideas?