You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have a script that requests thousands of pages from an API at a rate of 1 req/sec due to rate limits. This causes that the session token that is created after authenticating into the API expires multiple times during execution.
To solve that implemented a custom raise_for_status function that refreshes a session token after getting an HTTP 500 error response code due to faulty implementation of the API that I'm consuming. Here's a barebones (and redacted) copy of the relevant script functions:
importbackoffimportasyncioimportaiohttpasyncdefcustom_raise_for_status(response: aiohttp.ClientResponse):
ifresponse.status>=400:
ifresponse.statusin (403, 500):
logger.error("Token has expired. Refreshing...")
awaitrefresh_token(session=response._session)
else:
logger.error(f"Unexpected HTTP error code {response.status}")
raiseaiohttp.ClientResponseError(response.request_info, response.history)
# Token header is already defined in the session.asyncdefrefresh_token(session: aiohttp.ClientSession):
url=f"{API_URL}/auth_token/extend"asyncwithsession.get(url) asresponse:
assertresponse.status==200@backoff.on_exception(backoff.expo, aiohttp.ClientResponseError, max_tries=20, logger=logger)asyncdefget_api_endpoint(session: aiohttp.ClientSession):
url=f"{API_URL}/path/to/endpoint"asyncwithsession.get(url) asresponse:
data=awaitresponse.json()
# Do stuff with dataasyncdefmain():
# Do stuffheaders= {"Content-Type": "application/json", "charset": "UTF-8"}
ssl_context=ssl.create_default_context(cafile=certifi.where())
connector=aiohttp.TCPConnector(ssl=ssl_context)
asyncwithaiohttp.ClientSession(
headers=headers, raise_for_status=custom_raise_for_status, connector=connector
) assession:
logger.info("Logging in...")
awaitlogin(session=session)
awaitget_api_endpoint(session=session)
# Do more stuff
However, the reference to response._session is returning a None value.
To Reproduce
Implement the code showed previously.
Call to API responds with HTTP 500 after token expires.
An error ocurs.
Expected behavior
The HTTP 500 triggers raising ClientResponseError exception.
The backoff annotation calls the custom_raise_for_status function.
The response variable uses the reference to _session as a parameter to refresh the session token.
No exception is raised and the program continues.
Logs/tracebacks
on 585: ERROR:module.container_findings:Token has expired. Refreshing...
|███████▌⚠︎ | (!) 585/3139 [19%] in 9:50.4 (0.99/s)
+ Exception Group Traceback (most recent call last):
| File "C:\path\to\project\main.py", line 115, in <module>
| main()
| File "C:\path\to\project\main.py", line 101, in main
| count_container_findings(SCORE_CARD)
| File "C:\path\to\project\module\client.py", line 188, in count
| asyncio.run(main())
| File "C:\Users\user\AppData\Local\Programs\Python\Python312\Lib\asyncio\runners.py", line 194, in run
| return runner.run(main)
| ^^^^^^^^^^^^^^^^
| File "C:\Users\user\AppData\Local\Programs\Python\Python312\Lib\asyncio\runners.py", line 118, in run
| return self._loop.run_until_complete(task)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "C:\Users\user\AppData\Local\Programs\Python\Python312\Lib\asyncio\base_events.py", line 687, in run_until_complete
| return future.result()
| ^^^^^^^^^^^^^^^
| File "C:\path\to\project\module\client.py", line 178, in main
| hosts = await get_all_pages(session=session, pages=pages)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| File "C:\path\to\project\module\client.py", line 118, in get_all_pages
| async with GatheringTaskGroup() as tg:
| File "C:\Users\user\AppData\Local\Programs\Python\Python312\Lib\asyncio\taskgroups.py", line 145, in __aexit__
| raise me from None
| ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)
+-+---------------- 1 ----------------
| Traceback (most recent call last):
| File "c:\path\to\project\.venv\Lib\site-packages\backoff\_async.py", line 151, in retry
| ret =await target(*args, **kwargs)
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| File "C:\path\to\project\module\client.py", line 103, in get_api_endpoint
|asyncwith session.get(url) as response:
| File "c:\path\to\project\.venv\Lib\site-packages\aiohttp\client.py", line 1353, in__aenter__|self._resp =awaitself._coro
|^^^^^^^^^^^^^^^^| File "c:\path\to\project\.venv\Lib\site-packages\aiohttp\client.py", line 785, in _request
|await raise_for_status(resp)
| File "C:\path\to\project\module\client.py", line 57, in custom_raise_for_status
|await refresh_token(response._session)
| File "C:\path\to\project\module\client.py", line 74, in refresh_token
|asyncwith session.get(url) as response:
|^^^^^^^^^^^|AttributeError: 'NoneType'object has no attribute 'get'+------------------------------------
Describe the bug
I have a script that requests thousands of pages from an API at a rate of 1 req/sec due to rate limits. This causes that the session token that is created after authenticating into the API expires multiple times during execution.
To solve that implemented a custom
raise_for_status
function that refreshes a session token after getting an HTTP 500 error response code due to faulty implementation of the API that I'm consuming. Here's a barebones (and redacted) copy of the relevant script functions:However, the reference to
response._session
is returning aNone
value.To Reproduce
Expected behavior
ClientResponseError
exception.backoff
annotation calls thecustom_raise_for_status
function.response
variable uses the reference to_session
as a parameter to refresh the session token.Logs/tracebacks
Python Version
aiohttp Version
multidict Version
yarl Version
OS
Windows 11
Related component
Client
Additional context
No response
Code of Conduct
The text was updated successfully, but these errors were encountered: