aiohttp_retry
aiohttp_retry copied to clipboard
Add retry support for reading response body when chunked transfer encoding is enabled
Hello, here is an example I have been struggling with recently. When chunked transfer encoding is enabled on the server RetryClient isn't able to retry request in case of responses headers being correct but a problem occurred during body transmission (i.e. server lagged).
Here is a minimal example of the problem:
Server sleeps for 10 seconds during response if not retried enough:
class RetryCountingHandler:
def __init__(self, retries_before_response):
self.retries_left = retries_before_response
async def get_response(self, request):
response = web.StreamResponse()
response.enable_chunked_encoding()
await response.prepare(request)
self.retries_left -= 1
if self.retries_left >= 0:
await asyncio.sleep(10)
await response.write('Hello world'.encode('utf-8'))
return response
async def get_retries_left(self, request):
return web.Response(text=str(self.retries_left))
async def ping(self, request):
return web.Response(text='OK')
def run_server(url, port):
app = web.Application()
handler = RetryCountingHandler(retries_before_response=10)
app.add_routes([
web.get('/response', handler.get_response),
web.get('/retries_left', handler.get_retries_left),
web.get('/ping', handler.ping)
])
web.run_app(app, host=url, port=port)
Client side is a simple RetryClient:
async def get_text():
async with RetryClient(retry_options=aiohttp_retry.ListRetry([0.1] * 10, exceptions={Exception})) as session:
response = await session.get(f'{url}/response', timeout=0.1)
try:
print(await response.text())
except:
response = await session.get(f'{url}/retries_left')
print(await response.text())
raise
asyncio.run(get_text())
In this case a timeout exception will be raised during response.text()
but actual attempts count is 1.
Currently using urllib3 retries in requests library leads to the same behaviour but I believe that this functionality is especially important for retries in context of asynchronous library and this feature will be a strong reason to finally completely move from urllib3 to aiohttp.
The full minimal example is available in gist: https://gist.github.com/alexdrydew/c68a1b999ec57503e28f851cedf8e0eb