Best practices using Tokio spawn in library crate

I'm fairly new to rust and I can't find any documentation that lists the best practices when it comes to consuming Tokio inside a library crate.

I have a library crate that uses Tokio internally and needs to spawn tasks. Now,

  1. Is the crate supposed to be given an instance of a Tokio runtime when called?
  2. If so, how do you check that it has been configured properly for your needs?
  3. If not, how do you deal with a custom executor as part of the crate? (i.e. making sure it doesn't conflict with something else)
  4. What happens when other executors are involved, says the final binary uses futures::executor or async-std?
  5. When using future abstractions and exposing future traits as part of my API, does it matter which crate these are coming from? (e.g. I see a lot of things prefer futures::Stream over tokio::stream::Stream)
  6. Is there anything that helps abstracting the above and understood by most framework? (e.g. traits like futures::task::Spawn)
  7. Does it my crate API need to be async if I don't have an internal runtime?

The Tokio runtime has what is known as a context, i.e. any code running on the Tokio runtime (i.e. inside a tokio::spawn call) can access the runtime via a thread-local variable. This is what happens when you call the tokio::spawn method.

Typically you just call tokio::spawn, which panics if no Tokio runtime is present.

If you call tokio::spawn, your crate will only work if the caller uses Tokio. The alternatives involve creating a custom executor trait, allowing the user to give you an object with a spawn function. The other alternative is to return the future object and ask the caller to spawn it.

There is only one Stream and one Future trait, but the AsyncRead/AsyncWrite traits are different in futures vs tokio. There are conversion utilities in tokio-util::compat between the IO traits.

That trait exists, but no runtimes currently implement it. There are also crates with something similar, e.g. agnostik, but pretty much every crate I've seen with support for multiple runtimes do it by themselves instead of using one of the compatibility crates.

It depends on what your crate does. E.g. if you crate needs to perform IO, then it needs to be async if you want it to be usable in async projects, because otherwise your crate would be blocking the thread.

Thanks! this confirms more or less what I thought.

Typically you just call tokio::spawn , which panics if no Tokio runtime is present.

If one follows this simple approach and needs to integrates with a C binary, I would assume you still need to provide the option to create a runtime internally, correct?

Not necessarily. That depends a lot on the C library, and in any case, you would probably provide another layer on top of the library for the C FFI code.

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.