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

Add try_block_on method to allow calling sync functions from threads #6738

Closed
wants to merge 3 commits into from

Conversation

ashupednekar
Copy link

Motivation

The existing block_on function panics when used within a runtime context, preventing users from handling the situation appropriately. Specifically, it uses expect to panic, which does not allow users to take alternative actions, such as spawning a task when already in a runtime thread.

Solution

A new method, try_block_on, has been added. This method returns a Result instead of panicking, allowing users to handle the error case. The implementation checks whether the current thread can enter a blocking region. If it can, it runs the provided future; otherwise, it returns an error.

pub(crate) fn try_block_on<F: Future>(f: F) -> Result<F::Output, Box<dyn Error>> {
    match crate::runtime::context::try_enter_blocking_region() {
        Some(mut e) => Ok(e.block_on(f).unwrap()),
        None => Err("Cannot block the current thread from within a runtime. This \
        happens because a function attempted to block the current \
        thread while the thread is being used to drive asynchronous \
        tasks.".into())
    }
}

Idea is, users can handle this with a match or an if let and trigger spawn if needed.

@ashupednekar
Copy link
Author

Another course of action would be to make the try_enter_blocking_region function public

@Darksonn Darksonn added A-tokio Area: The main tokio crate M-runtime Module: tokio/runtime labels Aug 1, 2024
@Darksonn
Copy link
Contributor

Darksonn commented Aug 1, 2024

I'm a bit reluctant about this. I'm not convinced there are use-cases that are not hacks.

@ashupednekar
Copy link
Author

Here's the use case I'm facing at work... it's a bit niche... I understand if it's not mainstream...

So we're in the process of moving our codebase from python to rust, there's this crate called pyO3 which simplifies dynamic linking rust crates to python. Problem is, it doesn't support async functions, as of yet... so the python wrappers are synchronous relying on rt.block_on to invoke the actual async functionality.

Let's consider a scenario like, say... pubsub. The producer wrapper (sync) can be called from two places... directly from python, or through a consumer callback, which is already being invoked by an async tokio thread, hence the issue.

Again, this is very niche, just putting it out there.

@Darksonn
Copy link
Contributor

Darksonn commented Aug 1, 2024

Is there a reason that block_in_place with a block_on call inside does not work for you? You can use Handle::try_current() to handle the case where the runtime is completely missing.

@ashupednekar
Copy link
Author

ashupednekar commented Aug 1, 2024

That worked, thanks 😃

Didn't have to go for try_current since I always have a runtime.

@Darksonn
Copy link
Contributor

Darksonn commented Aug 1, 2024

Awesome! I'll close this PR since your issue is solved.

@Darksonn Darksonn closed this Aug 1, 2024
@ashupednekar
Copy link
Author

Cool

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

Successfully merging this pull request may close these issues.

2 participants