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

1 Like

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.
1 Like

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>:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.