Tonic: Support futures runtimes other than Tokio

Created on 24 Nov 2019  路  10Comments  路  Source: hyperium/tonic

Tonic seems to have made a large investment on Hyper and Tokio ecoystem. This had the side effect of making other runtimes not work well with tonic.

A basic demo of this can be created using on any of the tonic examples:

  1. Add async-std = { version = "1.1.0", features = ["attributes"]} to the dependencies list
  2. Replace #[tokio::main] with #[async_std::main]
  3. Run cargo run --example helloworld-client

An error message like this will appear:
Error: Error(Client, Error(Connect, Custom { kind: Other, error: "no current reactor" }))

So my open question: How can tonic better support using other non-tokio runtimes?

Most helpful comment

@xmclark hi! Tonic is still at an alpha release (soon to be 0.1) so its still early in the process. There are a few things that tie us to tokio/hyper, mainly the transport module which is behind a feature flag. The real abstracion for tonic is around tower-service and http-body crates which both do not tie to tokio/hyper. So in theory, if you have another http/2 implenetation you can just implement those abstractions and it will work.

The current reason why tonic is very tied to hyper/tokio is that the goal of this library was to provide a good out of box experience. This means we should try to optimize for users that may not have worked with futures/runtimes or even rust before. To achieve this there needs to be some form of tight coupling which is shown in the transport feature/module.

As for your issue directly, it looks like async-std doesn't provide the proper hooks to setup the tokio reactor/timer. So that is the error you are getting since the transport ties directly to tokio/hyper.

As far as I know there is no other http/2 implementation in rust besides hyper/h2 but if there were it is possible to swap them out which means runtime support as well.

As for now, I don't think there is much tonic can expose better to provide better interop. The transport module needs to be tightly coupled to support its feature set as of now. I think once we get closer to a more complete AsyncRead/AsyncWrite trait and tokio/hyper hit non alpha releases it will make sense.

That said, if you can get hyper to work with async-std it should be a very simple drop in. The transport module just provides more features than just hyper.

It may be worthwhile to better explain the higher-level abstractions that tonic provides.

I'd be happy to explore more and I am happy to review PRs that might be able to easily provide this ability but I don't quite see the easy path yet that wouldn't be very intrusive.

TL;DR: Tonic provides abstractions around tower-service and http-body that do not tie to tokio nor hyper, but the transport module/feature needs to be tightly coupled to provide its current feature set.

All 10 comments

@xmclark hi! Tonic is still at an alpha release (soon to be 0.1) so its still early in the process. There are a few things that tie us to tokio/hyper, mainly the transport module which is behind a feature flag. The real abstracion for tonic is around tower-service and http-body crates which both do not tie to tokio/hyper. So in theory, if you have another http/2 implenetation you can just implement those abstractions and it will work.

The current reason why tonic is very tied to hyper/tokio is that the goal of this library was to provide a good out of box experience. This means we should try to optimize for users that may not have worked with futures/runtimes or even rust before. To achieve this there needs to be some form of tight coupling which is shown in the transport feature/module.

As for your issue directly, it looks like async-std doesn't provide the proper hooks to setup the tokio reactor/timer. So that is the error you are getting since the transport ties directly to tokio/hyper.

As far as I know there is no other http/2 implementation in rust besides hyper/h2 but if there were it is possible to swap them out which means runtime support as well.

As for now, I don't think there is much tonic can expose better to provide better interop. The transport module needs to be tightly coupled to support its feature set as of now. I think once we get closer to a more complete AsyncRead/AsyncWrite trait and tokio/hyper hit non alpha releases it will make sense.

That said, if you can get hyper to work with async-std it should be a very simple drop in. The transport module just provides more features than just hyper.

It may be worthwhile to better explain the higher-level abstractions that tonic provides.

I'd be happy to explore more and I am happy to review PRs that might be able to easily provide this ability but I don't quite see the easy path yet that wouldn't be very intrusive.

TL;DR: Tonic provides abstractions around tower-service and http-body that do not tie to tokio nor hyper, but the transport module/feature needs to be tightly coupled to provide its current feature set.

I try to replace tonic Channel with my custom client, it built with async-std, however when I run, it still panic because the whole program still need tokio runtime. I dig codes and find maybe h2 crate depends on tokio and we can't replace h2 in tonic like replacing Channel

h2 only needs tokio because it uses tokio's io types and sync types. Otherwise, it should work on any other executor if you compat the traits correctly.

Do you have any progress with it?

Perhaps async-compat could help.

There are likely some hidden tokio spawns in this crate that will need to be refactored out. I don't currently have the time but happy to help mentor someone through it.

@LucioFranco what to do if that hidden tokio spawns inside dependencies?
For example, I found that spawn https://github.com/hyperium/hyper/blob/master/src/client/connect/dns.rs#L120
How to fix it? Do I need to fork hyper? How to pass runtime instance to that place?

Sorry for the dumb questions. I want to make it work.

A comment from @seanmonstar on providing your own runtime

As stated, by default hyper assumes the Tokio runtime is used. You can disable the default features, and provide your own connector for the Client.

^ right its a bit more lower level but you can swap out the places where we do this. The problem with using another runtime is that you don't get all the features that come with tonic's built in transport because it relies on tokio.

async_std runtime(Tokio dependencies are already built in)
Conditional compilation is already supported tokio02 and tokio03.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

LucioFranco picture LucioFranco  路  6Comments

blittable picture blittable  路  9Comments

petratbtl picture petratbtl  路  7Comments

LucioFranco picture LucioFranco  路  6Comments

matthauck picture matthauck  路  6Comments