-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
async: blocking client API #1346
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome.
My concerns can be summarized by this diff: https://paste.rs/W1Y. (https://paste.rs/W1Y.diff)
In short:
- Why not store the
Runtime
directly behind aMutex
? This way, we don't need a special dance to keep the runtime on ablock_on
. - I'd rather have the
self.inner = foo; self
in each method than the_map
. I don't care too much. In any case, the_map
can be written more cleanly as:self.inner = f(self.inner); self
. - I renamed
crate::local
asaio
just for my own sanity. This isn't a request.
I have ideas on how to clean things up re: documentation/duplication/keeping things in sync, but let's agree on an implementation first.
f04e68e
to
69bfc68
Compare
22a8120
to
1e01b9c
Compare
@SergioBenitez were you planning on adding more methods to |
@jebrosen Yes. I'm finishing off the |
@jebrosen Pushed! You'll see that I modified the deduplication macro to something that I believe is much cleaner and easier to work with. It also generates all of the examples, so no documentation is duplicated either, at the small cost of losing a bit of detail. Finally, I added an |
Yeah, this does look much easier to work with!
This begs the question: it obviously can't be |
@jebrosen The main reason I'd like to be #[async_test]
async fn test() {
let client = local::blocking:Client::new(rocket());
let res = client.get("/").dispatch();
} Otherwise, we'll be executing |
Ah. That's not actually sufficient, since the |
@jebrosen Of course. Bummer. I suppose a One idea is to insert a dummy #[async_test]
async fn test() {
let _rocket_inserted_await = dummy().await;
let client = local::blocking:Client::new(rocket());
let res = client.get("/").dispatch();
} Would love any other ideas you might have, or perhaps you feel that that this isn't something to be too concerned about? |
5294354
to
ea8218b
Compare
Alright! I believe, barring a few doc fixes, this is complete! I rebased on There are some sweeping changes here. Here's my attempt at iterating them:
@jebrosen Please do feel free to comment on any of this! |
This all looks really great!
I think all that's left to do is docs:
I will start those by copying text from the 0.4 docs, adding in words such as "asynchronous" or "blocking" as necessary. |
5141064
to
1bee5b1
Compare
Additionally use it in the form_kitchen_sink example and benches.
1bee5b1
to
4009306
Compare
@jebrosen Okay, I think I'm happy with this implementation + docs. I think the docs here strike a good balance between deduplication and having the relevant information in the right place. Would love for you to take a glance at the implementation, @jebrosen, see if I missed anything. Otherwise, I propose that we migrate all of the examples that can use the |
This looks great! I reviewed the documentation text and fixed one or two docs links, and I'm working on switching to |
…and in the guide.
Yeah. Unless I'm missing something, I'd say if we can use the blocking API, let's use it. |
Okay, minus the guide, I'm satisfied with merging this. If you'd like to take a crack at fixing up the guide for this, I'm happy to accept anything. I think we should effectively only discuss one of the two variants, ideally the blocking one, and then say, "You'll have noticed |
Alright, I've added a note (hopefully formatted correctly). We don't currently have any examples or tests where asynchronous dispatching actually makes a difference, so the example is a bit thin. |
I added an example where Funny enough, this revealed that Chrome doesn't concurrently dispatch two requests to the same server/path combo. Instead, it waits for the first to finish before dispatching the second. Thus, testing this example in the browser via two tabs to |
Very interesting. I replicated in Chromium, and Firefox sends the requests simultaneously. I expect that this behavior could depend on many factors in either browser, such as HTTP/2 and user configuration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent. Working on merging now.
Adds a blocking variant of the APIs in
rocket::local::
which is more convenient to use in testing. Most tests are currentlyasync
only because the API is, and the use of#[rocket::async_test]
and.await
s sprinkled throughout is just ceremony.An alternative approach could be to support only a blocking API and keep the
async
bits internal-only, but since requests can and will be executed concurrently in a live server I felt uncomfortable imposing this restriction. I believe that theasync
-capable test harness can be useful for simulating routes under load (e.g. interactions with databases or external APIs) without needing an HTTP client test harness.Implementation Overview
The blocking
Client
spawns a single background thread on construction. This thread runs a single-threadedtokio
Runtime
, and waits for a signal that the associatedClient
has been dropped. Methods on the blockingClient
,LocalRequest
, andLocalResponse
use the runtime'sHandle::block_on
method to expose a synchronous API on top of the existing asynchronousClient
. This is similar to the blocking API forreqwest
, but it takes advantage of the recently addedHandle::block_on
method intokio
to avoid an additional channel for communication to/from the runtime.Method signatures and documentation are simply copied from the blocking to the non-blocking version, and method bodies have been replaced with
client.block_on()
as necessary. Due to the large amount of similarity,diff -u client.rs blocking/client.rs
will be useful for reviewing this.Todo