Httpx: reutilisation of AsyncClient across multiple requests

Created on 2 Jul 2020  路  9Comments  路  Source: encode/httpx

Hi,

I wanted to ask about what is the recommended way to use the client when we are going to schedule multiple requests, specifically if its ok (safe), even recommended, to reuse the client instance (like shown in the example below)

Furthermore (after reading the usage of the client as a context manager) when and why would we want to close a client anyway and not leave it opened indefinitely for when someone calls for the next batch of concurrent requests ( to always get all those _significant performance improvements_ mentioned in the docs)

Here is a small example, where I never close the client nor I am using the context manager way, that might help in order to clarify what is good and/or wrong:

# client.py
class ExampleConcurrentClient:
    client = httpx.AsyncClient(headers=HEADERS, timeout=TIMEOUT)
    loop = asyncio.get_event_loop()

    async def _post(self, url, data, client):
        return await client.post(url, json=data)

    def _prepare_async_requests(self, requests):
        return asyncio.gather(*[self._post(request["url"], request["data"]) for request in requests])

    def post_all(self, targets, data):
        # ... build requests
        responses = self.loop.run_until_complete(self._prepare_async_requests(requests))
        return responses

concurrent_client = ExampleConcurrentClient()
# user_actions.py
from client.py import concurrent_client

#after some time t0 someone calls again:
concurrent_client.post_all(targets=..., data=...)

# after some time t0+1 someone calls again:
concurrent_client.post_all(targets=..., data=...)

# after some time t0+2 someone calls again:
concurrent_client.post_all(targets=..., data=...)

Thanks in advance.

question

All 9 comments

Hi,

Not sure what your question is exactly, but your approach looks good. It鈥檚 safe to have a shared client and reuse it for the lifetime of your program. From my experience closing the client when the program exits is better, but if your program is a long running server then you can most likely just skip that part.

Hope this answers your question. Going to close this for now but feel free to drop by the chat if you have more questions or want to follow up. :)

I wanted to ask about what is the recommended way to use the client when we are going to schedule multiple requests, specifically if its ok (safe), even recommended, to reuse the client instance

It's more than safe, it's the sensible thing to do.

You shouldn't really need to wrap the client up in the way you've done here, instead just create a single global client instance, and use that throughout...

# This is absolutely fine
client = httpx.AsyncClient(headers=HEADERS, timeout=TIMEOUT)

Thanks for the quick answers @florimondmanca and @tomchristie ! The docs had threw me off a bit by the recommended usage as a context manager.

you clarified what I needed to know:

  • it is recommended to keep the client open for the lifetime of the program, no need to close it/ clean connections.
  • the client can be passed around and reused as pleased with no limitations.

Cheers.

no need to close it/ clean connections.

_Personally_ I would find a way to client.aclose() when the program exits (eg for a Starlette app, by registering a shutdown event handler), at least for the sake of correctness, but no need to sweat it either I guess.

Yeah, I'd echo @florimondmanca's comment here.

for the sake of correctness

Yeap absolutely, that was my plan as well after reading the first responses. 馃憤

I don't get this.. if this is the sensible way to do things, why not have that singleton in httpx itself?

It's kinda weird to write libraries that use httpx because you either gotta pass around the client object from the library's user, or use a singleton specific to the library.

What's the preferred way?

Which Python HTTP library has a significantly different API here, that you think httpx ought to be following from? Or what alternate API do you think should be introducing?

Having the client instance be the scope over which the connection pool is maintained/ released is pretty standard stuff. We're not doing anything unusual here.

Hey Tom, thanks for responding. I see your point, in that this is what every other library makes you do anyway.

But I was just imagining the possibility of a shared singleton AsyncClient provided by httpx, so an end user, if I'm using 5 libraries that use httpx, then all my connections are automatically pooled because of this programming convention change.

Was this page helpful?
0 / 5 - 0 ratings