Create inner tasks without explicitly provide a async runtime

I’m building a runtime agnostic mock server, for now, I manage to get it running for the two most popular async runtimes in rust.

The problem is, code is not too much reusable, and there’s potential to do so, but in order to do that, I can’t simply call something like tokio::spawn, but something like executor.spawn, where executor represents async runtime somehow.

Is that a good path to take? Am I going through wrong path?

There are a bunch of libraries trying to facilitate runtime agnosticism. So I'd say it is pretty much something that the community wants. Some (more or less) popular ones are listed under the #async-executor keyword on lib.rs:

Maybe you can use them as is, or contribute to one (e.g. executor-trait) if it doesn't support a runtime you want to enable in your project.

In my case, in want support tokio and smol.

The async-rs library supports both, maybe give that one a try?

Looks like exactly what I need, except for the fact it has MSRV of 1.85, which is pretty high.

1.85 is almost a year old by now. I wonder what's the motivation for using something older?

Can you just take spawn as a closure? MSRW would probably hurt though. You could also create an async trait packed with different functions and have all your functions as generic, it is quite workable tbh.

1 Like

Do you have to make it un-cancellable?

spawn is not needed for anything except to make a given future keep running even after the future that spawned it has been cancelled and can't observe the result any more.

99% of the time I see spawn used only to decouple running of a future from async control flow around it, which is convenient, but an unnecessary use of spawn.

Otherwise, if you merely need to run multiple things concurrently, use join!, join_all, and keep returning async blocks that use these to "spawn" other futures.

Every async fn that executes code already runs on a runtime and can run more futures on that runtime with .await!

After read async-rs and others, I decided to simply crate a wrapper on top of tokio::spawn and smol::spawn, then I create a small utility struct named ServerTask to keep a reference to either JoinHandle on tokio and Task on smol, that did the trick.