Skip to content

macros: add "local" runtime flavor #7375

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

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

Conversation

Twey
Copy link

@Twey Twey commented May 30, 2025

Motivation

We would like to be able to create a local runtime from the tokio::main attribute in order to be able to use spawn_local in functions that rely on tokio::main or tokio::test.

Solution

Add a local flavor to tokio::main which behaves like current-thread, but calls build_local(Default::default()) instead of build().

@Darksonn Darksonn added A-tokio-macros Area: The tokio-macros crate M-runtime Module: tokio/runtime labels May 31, 2025
@Darksonn Darksonn requested a review from carllerche May 31, 2025 11:39
@Darksonn
Copy link
Contributor

Darksonn commented Jun 3, 2025

Can you please make sure that CI passes? There's a rustfmt failure.

@Twey
Copy link
Author

Twey commented Jun 3, 2025

Thanks for taking the time to review @ADD-SP @Darksonn! I think I've addressed your comments. Would you mind taking another look?

Copy link
Contributor

@Darksonn Darksonn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about the delay in review.

let msg = format!(
"The `worker_threads` option requires the `multi_thread` runtime flavor. Use `#[{}(flavor = \"multi_thread\")]`",
self.macro_name(),
);
return Err(syn::Error::new(worker_threads_span, msg));
}
(F::CurrentThread, None) => None,
(F::CurrentThread | F::Local, None) => None,
(F::Threaded, worker_threads) if self.rt_multi_thread_available => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add logic to rt_multi_thread_available to detect whether --cfg tokio_unstable is set and emit a hard error if it is not.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand this comment. Did you mean to add the logic to RuntimeFlavor::from_str?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error should be similar to this error:

let msg = if self.flavor.is_none() {
"The default runtime flavor is `multi_thread`, but the `rt-multi-thread` feature is disabled."
} else {
"The runtime flavor `multi_thread` requires the `rt-multi-thread` feature."
};

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you meant a0ca77e; if I've misinterpreted please feel free to suggest changes :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I just saw your comment. Is 4363203 more what you had in mind?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both are okay.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is harder than it appears because RUSTFLAGS is not passed to proc macros. I guess we have to emit a cfg check, so it actually can't live in either of these places.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

44a31b1 seems to work in my local tests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't that also trigger other unrelated errors when it fails?

What we do today is essentially define the main macro two times to pass different values to the rt_multi_thread boolean, and have lib.rs do this:

#[cfg(feature = "rt-multi-thread")]
pub use tokio_macros::main;
#[cfg(not(feature = "rt-multi-thread"))]
pub use tokio_macros::main_rt as main;

This way, the macro knows based on the cfgs that apply in the main Tokio crate. We could use the same approach and have four macros.

@carllerche
Copy link
Member

This looks fine to me. I'm happy to merge this when @Darksonn is. Are there docs? My main concern is explaining to users the difference between flavor local and flavor current_thread and how to pick between them.

@Twey
Copy link
Author

Twey commented Jun 21, 2025

Is there a reason to use current_thread over local when it's available?

@Darksonn
Copy link
Contributor

@Twey I'm pretty reluctant to change the default runtime. I do not want a repeat of #4142 where we had to revert something.

@Twey
Copy link
Author

Twey commented Jun 23, 2025

I'm happy enough to not change the default runtime — but I'm not really clear on what I should write in the documentation about when to choose current_thread over local.

@Twey
Copy link
Author

Twey commented Jun 23, 2025

I'm not certain I've done the right thing but I've done my best :) Please feel free to suggest further changes if I didn't understand something correctly.

///
/// Equivalent code not using `#[tokio::main]`
///
/// ```ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work?

Suggested change
/// ```ignore
/// ```
/// #![cfg(tokio_unstable)]

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it will be executed. We could use text but then we lose Rust highlighting.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can execute it, then I think we should. Why can't we?

Copy link
Author

@Twey Twey Jun 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do b040de5.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't execute it because the LocalExecutor doesn't exist if we don't have tokio_unstable, which we don't usually have in tests. But maybe it's clearer this way anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we add a cfg(tokio_unstable) to the test so it only actually runs under tokio_unstable? I believe we run tests both with and without the flag.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, that's b040de5 :)

@Twey Twey force-pushed the local-macro branch 3 times, most recently from b1f3a19 to 44a31b1 Compare June 24, 2025 13:19
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The permission of this file is updated too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio-macros Area: The tokio-macros crate M-runtime Module: tokio/runtime
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants