Tokio runtimes and tokio::sync::OnceCell

Hi,

I have a global crate exposing convenience functions to get data from a database using async functions (bb8_tiberius). This crate is used by multiple other crates (binaries) to provide an easy api in my code to access data, e.g.:

pub async fn get_user_by_id(id: i64) -> Result<String, Error> { .... }

Now, in order to get good performance for database connetions I initialize a global connection pool and in every accessor function (e.g. get_user_by_id from above) get the pool out of a tokio::sync::OnceCell.

This works fine in all my applications - but creates a problem for tests, as it seems as #[tokio::test] creates a runtime for each individual test => I get " An error occured during the attempt of performing I/O: An error occured during the attempt of performing I/O: A Tokio 1.x context
was found, but it is being shutdown" errors whenever i try to run more then one test at a time.

My investigation leads me to beleive this is because the OnceCell is tied to one particualr runtime?

My question is twofold:

  1. Is it possible to create a OnceCell (with lazy initialization) that works across multiple runtimes?
  2. Alternatively - is it possible to get tokio to re-use the runtime across tests?

Regards Viktor

The OnceCell type is not tied to the runtime. It is probably the value you're storing inside the OnceCell that's tied to the runtime.

1 Like

Hmm thanks - ok - it's probably the database pool then :frowning:

Do you know if it's possible to run the tests so they either use the same runtime or "create new" OnceCell values?

/V

If the OnceCell is defined in your test, then you could put the OnceCell in a thread-local since tests use a single-threaded runtime meaning that there's a one-to-one mapping from thread to runtime. However, if it's defined in the library, then that might not work.

Other options would be:

  1. Put a runtime in a (non-async) OnceCell and have each test use #[test] + a block_on on the shared runtime. (I.e. you're not using #[tokio::test])
  2. Remove the global from your library and have it be an argument. Then create a separate value in each test.

Nice! Yes putting a runtime in a once cell is a nice idea, thanks! (It’s indeed in a library where making it an argument is effectively impossible)

tors 23 mars 2023 kl. 14:49 skrev Alice Ryhl via The Rust Programming Language Forum <notifications@rust-lang.discoursemail.com>: