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

Async POST blocks forever #500

Closed
onelson opened this issue Apr 19, 2019 · 3 comments
Closed

Async POST blocks forever #500

onelson opened this issue Apr 19, 2019 · 3 comments

Comments

@onelson
Copy link

onelson commented Apr 19, 2019

I'm wondering if my usage isn't supported because of implementation details in the thread pooling or something.

I'm hoping to hold an async Client in a struct with some additional configuration in it.

struct ApiClient {
  // ...
  client: reqwest::r#async::Client,
  // ...
}

impl ApiClient {
  // ...
  fn authenticate(
        &self,
        form_data: &[(&str, &str)],
    ) -> impl Future<Item = Value, Error = ShotgunError> {
        self.client
            .post(&format!("{}/api/v1/auth/access_token", self.sg_server))
            .form(form_data)
            .header("Accept", "application/json")
            .send()
            .from_err()
            .and_then(|mut resp| resp.json::<Value>())
            .map_err(ShotgunError::from)
  }
  // ..
}

Everything seems to work fine, except that if I call this method and pass it to tokio::run(), the request fires, the response comes back, but tokio blocks forever.

Is there any special consideration I need to make to have this work?

@seanmonstar
Copy link
Owner

tokio::run executes and blocks until all spawned futures complete. The client's connection pool spawns a future to observe if the connection gets closed so as to remove it from the pool. That future would be dropped when the client drops, but if execution is blocked on tokio::run they'll keep each alive.

@onelson
Copy link
Author

onelson commented Apr 19, 2019

Hmm. I'm not sure what I can do then. I'd like to keep a single Client alive to reuse it during the lifetime of my API client. I'll try and pass a client in with each method and see if that leads to a workable option. Seems like that'd give me the same problem, however.

Maybe I can force it.

@onelson
Copy link
Author

onelson commented Apr 19, 2019

OK, so it looks like I can sort of:

let work: Future<I, E> = {
// build my client, pass it into my struct to build all my futures
// then return my future
};
tokio::run(work);

This should satisfy the need to drop the client before running the task. It'll probably make the usage a good amount more fiddly for the caller, but I suppose it's not much different than working with a database connection.

I can likely sweeten this for the caller with a little more thought and work. Thanks!

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

No branches or pull requests

2 participants