Best way to use httpx async client and tenacity?

3.3k views Asked by At

I'm getting fairly different results with two different implementations.

Here is implementation 1

request_semaphore = asyncio.Semaphore(5)
async def _send_async_request(client: AsyncClient, method, auth, url, body):
  async with request_semaphore:
    try:
      async for attempt in AsyncRetrying(stop=stop_after_attempt(3), wait=wait_fixed(1)):
        with attempt:    
          response = await client.request(method=method, url=url, auth=auth, json=body)
          response.raise_for_status()
          return response
    except RetryError as e:
      pass

And here is implementation 2:

request_semaphore = asyncio.Semaphore(5)
@retry(stop=stop_after_attempt(3), wait=wait_fixed(1))
async def _send_single_async_request(self, client: AsyncClient, method, auth, url, body):
  async with request_semaphore:
    response = await client.request(method=method, url=url, auth=auth, json=body)
    response.raise_for_status()
    return response

async def _send_async_request(self, client: AsyncClient, method, auth, url, body):
  try:
    await self._send_single_async_request(client, method, auth, request)
  except RetryError as e:
    pass

I'm testing it against a stable REST API. Here are the bench marks:

  1. 100 successful POST requests:
  • Implementation 1: 0:59 mins
  • Implementation 2: 0:57 mins
  1. 100 failed POST requests:
  • Implementation 1: 3:26 mins
  • Implementation 2: 2:09 mins

These results are consistent. Can anyone help me understand why my first implementation is slower than my second?

edit: FYI, here's how i'm calling the above functions (the above funcs actually receive a request tuple with url and body, edited it for clarity)

async def _prepare_async_requests(method, auth, requests):
    async with AsyncClient() as client:
      task_list = [self._send_async_request(client, method, auth, request) for request in requests]
      return [await task for task in asyncio.as_completed(task_list)]

def send_async_requests(auth, method, requests):
    loop = asyncio.get_event_loop()
    responses = loop.run_until_complete(self._prepare_async_requests(method, auth, requests))
    return responses
0

There are 0 answers