Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop async_trait #1556

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Drop async_trait #1556

wants to merge 2 commits into from

Conversation

matze
Copy link
Contributor

@matze matze commented Oct 23, 2023

Motivation

This change was born mostly out of curiosity rather than a serious attempt to get it in any time soon. The main motivation of course is to get rid of the async_trait macro and boxed futures in favor of recently stabilized async fn in traits.

Solution

Remove usage of the async_trait macro and adjust the server codegen parts to return desugared impl Future<…> + Send because of the Send bound problem.

Caveats

This requires a nightly compiler but with that passes all tests as well as some manual tests I performed.

The larger question to answer though is how this would be merged into tonic eventually. tonic-health and tonic-reflection rely on generated code which prohibits a gradual, feature-based integration. Moreover, this would require quite a large bump of MSRV to 1.75.

@LucioFranco
Copy link
Member

@matze Nice! I think we could potentially offer this as an opt-in during codegen? I don't think there is anything stopping us from support both since its mostly codegen and user callsite code that is affected. What do you think?

@matze
Copy link
Contributor Author

matze commented Oct 27, 2023

If I understand correctly and in order to have mid-term compatibility means adding a separate flag async_trait that is automatically enabled with codegen? Even easier, if codegen is on but async_trait not, then this one here could kick in. Should indeed make the PR much smaller as well and be green. Let me try :-)

@matze
Copy link
Contributor Author

matze commented Oct 27, 2023

@LucioFranco I tested but the initial caveat still holds, all crates using pre-generated services require either async_trait or a nightly compiler. And emitting code with the feature flag check in place does not work either.

@matze
Copy link
Contributor Author

matze commented Nov 15, 2023

A similar PR is approved for axum, how do you think just breaking as well?

@LucioFranco
Copy link
Member

@LucioFranco I tested but the initial caveat still holds, all crates using pre-generated services require either async_trait or a nightly compiler. And emitting code with the feature flag check in place does not work either.

I am not following what you mean by this?

A similar tokio-rs/axum#2308 is approved for axum, how do you think just breaking as well?

I think we should if we can get it so it works for both and users can choose.

@matze
Copy link
Contributor Author

matze commented Nov 16, 2023

I am not following what you mean by this?

I mean I don't see how this could ever work for both. tonic-health and tonic-reflection contain pre-generated implementations that either fit a hypothetical feature flag that represents async-trait-less tonic or not. I mean we could go back to the times when tonic-health and tonic-reflection were generated at build time but I guess you had good reasons to not do so.

@daniel-levin
Copy link

Firstly let me say that I don't want to come across as prescriptive. Like many others, I'd like to see async_trait deprecated because it was a (very good) workaround for a shortcoming in Rust itself. Now that that shortcoming has been addressed, the continued use of async_trait comes with a trade-off between not breaking users and performance. I love and appreciate that @LucioFranco wants to bend over backwards to not break users. Too many hours have been wasted by less conscientious open source maintainers who don't mind breaking their users.

However, async_trait must eventually go away. The crux of the issue is where the burden of responsibility falls. Do you break your users in the name of performance? Do you maintain feature flag gymnastics to support both? If so, for how long?

In my view, tonic should draw a line in the sand, beyond which async_trait will be dropped.

I'd like to see tonic stamp out a new major version (the fabled 1.0, perhaps?) that drops async_trait, while studiously maintaining an older branch and version still using async_trait, until some cut-off date. In the interim, the deprecation of the older version should be communicated as widely as possible. Let everyone know, async_trait is going away, but you can upgrade at your convenience.

This is a lot of work for the tonic maintainers. This is potentially a lot of work for tonic users. But, I think it balances the trade off without unduly burdening anyone.

  1. Tonic won't suddenly externalize the burden of dropping async_trait and break users.
  2. Users will get time to upgrade.
  3. All dependents (and there are a lot) are freed from needing to depend on async_trait as well.

@djc
Copy link
Collaborator

djc commented Jul 22, 2024

Ultimately I think the constraints here are:

  1. MSRV: we want to support a version of tonic that doesn't need GAT until we decide we no longer want to support the old compiler versions
  2. Minimize maintenance overhead

At the same time, I do wonder what the motivation is to get rid of async-trait? Have you measured a large effect on performance in your workloads? Or a large effect on compile-time due to the extra macros/dependency?

@matze
Copy link
Contributor Author

matze commented Jul 22, 2024

If axum is any indication, latency and throughput improved measurably but not with "large effect". For me personally this is of lower priority, not having to deal with generated, intransparent code is more important especially if there are alternatives out-of-the-box.

@LucioFranco
Copy link
Member

Obviously, we would like to drop it eventually, but the current state of async traits is not in its final state and it has a few issues that are left to be resolved before I would even consider it something to widely support in a library like this. Unless someone can put forth some valid data showing that there is a legit perf improvement to dropping async-trait then I don't think its worth investing on this right now versus other streams of work for tonic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants