Search code examples
pythonaiohttp

Aiohttp: `async with session.get(...)` block blocks until receiving the request: why?


I have following code snipped:

import aiohttp
import asyncio

async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://hub.dummyapis.com/delay?seconds=1") as r:
            print("Here!")
            text = await r.text()
            print(text)

asyncio.run(main())

The url I'm calling simply waits for one second, and then returns a 200.

I thought the Here!, would be printed immediately, then 1 second would pass (or maybe a tiny bit more, including the overhead to send and receive the request), and then the text will be printed. After all, I'm only awaiting after the print("Here!") statement. But that's not the case, the Here! is only printed after 1 second. So i guess that the async with session.get(...) as r is blocking? My questions:

  1. What's going on here? Is it an implementation detail of aiohttp to wait for the response to be received, or am I misunderstanding async here? Can I make the session.get(...) as r unblocking?
  2. More specifically, I would like to be able to:
  • First send the request, saving a Future/awaitable (or something else?) that will resolve to a response for later.
  • Do some work - which uses that Future/awaitable (specifically I would like to inspect the state of the request when it's in-flight)
  • wait for the response to come through, and return

Is that possible with aiohttp?


Solution

  • Basically it is an internal implementation. Lets investigate aiohttp implementation and start with following line of the code

    async with session.get("https://hub.dummyapis.com/delay?seconds=1") as r:
    

    Get method of ClientSession returns a context manager called _RequestContextManager here. If you check this context manager, it is inherited from another context manager called _BaseRequestContextManager. In the __aenter__ of this context manager, it basically awaits the response of request and returns response. So basically with this line, you already did request to server and it waited for 1 seconds to get response. So it is normal that "Here!" is printed after 1 seconds because the code inside the context manager is executed after response is obtained. If you check, text method of ClientResponse, you can see that this methods only gets body of response and decodes it.