-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
0.6.0: Pool::close does not completely close when awaited #1928
Comments
Hey, so I run into this just now with my similarly custom funky test harness. I was able to home the issue to the usage of the Good day. |
Thanks for taking the time to look at my code, do you mean that you were using tokio as an executor but used async-std |
Having a similar issue for an identical use case, it's not just macOS. I have issue on docker setup as well. However, my issue with postgres, |
@TimDeve Not all futures are portable across runtimes even if the runtimes are from the same library and in some cases, even if they're configured identically. In this case, the connections in the pool are being spawned and used in the probably multi threaded sophisticated runtime your app is using but you're trying to close them on a simple |
I believe this is what you are suggesting: No However the error is still there. It seems the refactoring of
It clearly doesn't wait otherwise the following error wouldn't happen:
|
I'm confused what you mean here. If you don't put the cleanup calls in the Drop impl, then on failure the database won't be cleaned up. Unfortunately, Drop isn't async so we must create a separate runtime. Which causes issues with closing pools (at least with postgres). |
After some additional testing it seems the problem doesn't happen if the pool has been dropped, so a potential workaround if your setup is similar (a Pool field in a struct where you've defined Drop) then wrapping Pool in a Option and setting that to None once you have called Here's an example in Gist. I'm trying to figure out what has changed in the sqlx source code to cause that but I've not found it yet. |
Ah you're right we have opposite problem it seems? Mine is that |
There is a regression in sqlx v0.6 where `Pool::close` does not actually close all connections, after some investigation it was found that the pool that was held in the Scaffold struct also needed be dropped to properly close _all_ connections. See launchbadge/sqlx#1928
Yes, this is correct. Sorry I forgot to mention that. The builtin test runner also has this as a "feature" for debugging sakes. But this got me curious and the internal impl of
Curious. You can see what worked for me here and here. I did try dropping the pool first but it did not help. After some investigation, I see that the async-std |
No, it does not. It references the Tokio runtime set for the current thread the code is executing on (
They are not, and Tokio actually does not like it when you move
That is a deliberate feature, yes. If you have a test failure, it's useful to go back and look at the contents of the database to help figure out what went wrong. They won't pile up forever, though. Old test databases are cleaned up every time on startup of any binary using I had intended to add commands to All that aside, I've realized that there's likely a TOCTOU bug in Specifically, here: https://github.com/launchbadge/sqlx/blob/main/sqlx-core/src/pool/inner.rs#L257 If It used to acquire I think the fix here would be to change That should eliminate the possibility of |
@abonander Have you been able to find any details with the postgres issue? or is it simply unsupported because of tokio? |
The original issue concerns async-std, not Tokio. The discussion as a whole has been muddied quite a bit because of that. Regarding Tokio, using a separate runtime to close the pool is likely going to break things so I would avoid doing that. You should also never use A minimal example reproducing the issue would be a big help. |
@abonander I can create a new issue if need be. Here's an example: use sqlx::migrate::MigrateDatabase;
use sqlx::postgres::PgPoolOptions;
use sqlx::{Executor, Pool, Postgres};
use std::{env, thread};
use tokio::runtime::Runtime;
use uuid::Uuid;
struct TempDb {
pool: Option<Pool<Postgres>>,
db_url: String,
}
impl TempDb {
pub async fn new() -> TempDb {
let db_url = format!("{}/{}", env::var("DB_URL").unwrap(), Uuid::new_v4());
Postgres::create_database(&db_url).await.unwrap();
let pool = PgPoolOptions::new()
.max_connections(5)
.connect(&db_url)
.await
.unwrap();
Self {
pool: Some(pool),
db_url,
}
}
pub fn pool(&self) -> &Pool<Postgres> {
self.pool.as_ref().unwrap()
}
}
impl Drop for TempDb {
fn drop(&mut self) {
let pool = self.pool.take().unwrap();
let db_url = self.db_url.clone();
thread::spawn(move || {
let runtime = Runtime::new().unwrap();
runtime.block_on(async {
println!("inside runtime");
pool.close().await;
println!("closed");
drop(pool);
println!("dropped");
Postgres::drop_database(&db_url).await.unwrap();
println!("dropped db");
});
})
.join()
.expect("thread failed");
}
}
#[tokio::test]
pub async fn example() {
let db = TempDb::new().await;
let pool = db.pool();
pool.execute("SELECT 1").await.unwrap();
} |
Thank you @abonander for looking into this. |
@jbis9051 yeah, you're deadlocking the Like I said on Discord, I recommend using |
I have a somewhat-hackish setup to create a test database for every integration tests, on struct creation it creates the database with a connection pool and on drop it closes the pool before deleting the database. (Side Note: if someone has a better way of doing that I am definitely interested)
Since upgrading to v0.6.0 the database drop fails because there is still connections open:
It only seems to happen on MacOS (I have not tested locally on Linux but here is a CI run demonstrating the problem).
I have not been able to create a small example that demonstrate the problem, following is my attempt that does not exhibit it.
Simple example
My guess would be that because I am passing the pool to tide's context it's being held longer that in my simple example as when I create a test that only creates the scaffold and makes a call to the database without creating a tide application the problem does not happen.
I have added a call to
Pool::size
after an awaitedPool::close
, in v0.5 it is consistently equal to 0 while in v0.6 it is always equal to 1.The text was updated successfully, but these errors were encountered: