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

register_blocking_method #523

Merged
merged 10 commits into from
Oct 15, 2021
Merged

register_blocking_method #523

merged 10 commits into from
Oct 15, 2021

Conversation

maciejhirsz
Copy link
Contributor

Potentially fixes #486.

Not sure where a good place to document the blocking flag in the #[method] macro attribute would be?

@dvdplm
Copy link
Contributor

dvdplm commented Oct 14, 2021

Not sure where a good place to document the blocking flag in the #[method] macro attribute would be?

Somewhere here I think would be a good place, possibly also with a machine checked example.
I think we should provide the motivation for when it is appropriate to use this, and what the trade-offs are.

@@ -466,6 +466,43 @@ impl<Context: Send + Sync + 'static> RpcModule<Context> {
Ok(MethodResourcesBuilder { build: ResourceVec::new(), callback })
}

/// Register a new **blocking** synchronous RPC method, which computes the response with the given callback.
/// Unlike the regular [`register_method`](RpcModule::register_method), this method can block its thread and perform expensive computations.
pub fn register_blocking_method<R, F>(
Copy link
Contributor

Choose a reason for hiding this comment

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

Soon we'll be at a point where we should have a macro for all these register_* methods... :)

}

// Each request takes 50ms, added 10ms margin for scheduling
assert!(elapsed < Duration::from_millis(60), "Expected less than 60ms, got {:?}", elapsed);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm hard pressed to come up with something better than this. It'll have to make do.

Copy link
Contributor Author

@maciejhirsz maciejhirsz Oct 14, 2021

Choose a reason for hiding this comment

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

Right now on MacOS CI 50ms + 50ms in parallel = 160ms though :D

let ctx = self.ctx.clone();
let callback = self.methods.verify_and_insert(
method_name,
MethodCallback::new_async(Arc::new(move |id, params, tx, claimed| {
Copy link
Member

@niklasad1 niklasad1 Oct 14, 2021

Choose a reason for hiding this comment

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

dq: Why can't we do new_sync i.e, the closure itself is synchronous?

hrm, I assume using tokio::spawn_blocking is more efficient than std::thread::spawn because tokio is already initialized when the server is started?

Should we have a way to register an async closure too or is that the footgun you were talking about?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

dq: Why can't we do new_sync i.e, the closure itself it synchronous?

hrm, I assume using tokio::spawn_blocking is more efficient than std::thread::spawn because tokio is already initialized when the server is started?

Yeah, tokio will manage a threadpool for blocking tasks, spawning OS threads can be costly (pending on how blocking the callback really is). That said, we can probably go with new_sync here anyway, I thought we need to track the future to completion, but we don't really...

Should we have a way to register an async closure too or is that the footgun you were talking about?

Yeah, that's the footgun. Would have to wrap the async callback into something like LocalSet that's bound to the thread, but the moment you do some .await on something that might be expecting a regular tokio runtime (for io or timers or something) I'm not sure exactly what would happen, but I wouldn't be surprised to see a panic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Tried to make it work with sync callback, but there are some assumptions about lifetimes for params sync callback makes, plus it also means I need to pass in claimed resources handler, so all in all using async callback is way less invasive for what is ultimately a niche feature.

utils/Cargo.toml Outdated Show resolved Hide resolved
Copy link
Member

@niklasad1 niklasad1 left a comment

Choose a reason for hiding this comment

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

LGTM

@maciejhirsz maciejhirsz merged commit 50b172e into master Oct 15, 2021
@maciejhirsz maciejhirsz deleted the mh-register-blocking-method branch October 15, 2021 09:25
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.

Offloading JSON serialization for huge payloads
3 participants