11
11
logging .basicConfig (level = logging .INFO )
12
12
13
13
SLEEP_TIME_ON_429 = 5
14
+ MAX_RETRIES_ON_429 = 20
15
+
16
+
17
+ def retry_on_429 (func : Callable [..., Awaitable ]) -> Callable [..., Awaitable ]:
18
+ """Decorator that retries requests that receive a 429 status code."""
19
+ async def wrapper (* args , ** kwargs ) -> httpx .Response :
20
+ retries = 0
21
+ while retries < MAX_RETRIES_ON_429 :
22
+ response = await func (* args , ** kwargs )
23
+ if response .status_code != 429 :
24
+ return response
25
+
26
+ retries += 1
27
+ await asyncio .sleep (SLEEP_TIME_ON_429 )
28
+
29
+ return response
30
+ return wrapper
14
31
15
32
16
33
class LoopCommunicationException (Exception ):
@@ -98,19 +115,17 @@ async def get(self, path: str, requires_login: bool = True, api_prefix: str = '/
98
115
return await self .retry_on_401 (self ._get , path , api_prefix )
99
116
return await self ._get (path , api_prefix )
100
117
118
+ @retry_on_429
101
119
async def _get (self , path : str , api_prefix : str ) -> httpx .Response :
102
- response = await self .async_client .get (api_prefix + path )
103
- while response .status_code == 429 :
104
- await asyncio .sleep (SLEEP_TIME_ON_429 )
105
- response = await self .async_client .get (api_prefix + path )
106
- return response
120
+ return await self .async_client .get (api_prefix + path )
107
121
108
122
async def put (self , path : str , files : Optional [List [str ]] = None , requires_login : bool = True , api_prefix : str = '/api' , ** kwargs ) -> httpx .Response :
109
123
if requires_login :
110
124
await self .ensure_login ()
111
125
return await self .retry_on_401 (self ._put , path , files , api_prefix , ** kwargs )
112
126
return await self ._put (path , files , api_prefix , ** kwargs )
113
127
128
+ @retry_on_429
114
129
async def _put (self , path : str , files : Optional [List [str ]], api_prefix : str , ** kwargs ) -> httpx .Response :
115
130
if files is None :
116
131
return await self .async_client .put (api_prefix + path , ** kwargs )
@@ -127,9 +142,6 @@ async def _put(self, path: str, files: Optional[List[str]], api_prefix: str, **k
127
142
try :
128
143
file_list = [('files' , fh ) for fh in file_handles ] # Use file handles
129
144
response = await self .async_client .put (api_prefix + path , files = file_list )
130
- while response .status_code == 429 :
131
- await asyncio .sleep (SLEEP_TIME_ON_429 )
132
- response = await self .async_client .put (api_prefix + path , files = file_list )
133
145
finally :
134
146
for fh in file_handles :
135
147
fh .close () # Ensure all files are closed
@@ -142,22 +154,16 @@ async def post(self, path: str, requires_login: bool = True, api_prefix: str = '
142
154
return await self .retry_on_401 (self ._post , path , api_prefix , ** kwargs )
143
155
return await self ._post (path , api_prefix , ** kwargs )
144
156
157
+ @retry_on_429
145
158
async def _post (self , path , api_prefix = '/api' , ** kwargs ) -> httpx .Response :
146
- response = await self .async_client .post (api_prefix + path , ** kwargs )
147
- while response .status_code == 429 :
148
- await asyncio .sleep (SLEEP_TIME_ON_429 )
149
- response = await self .async_client .post (api_prefix + path , ** kwargs )
150
- return response
159
+ return await self .async_client .post (api_prefix + path , ** kwargs )
151
160
152
161
async def delete (self , path : str , requires_login : bool = True , api_prefix : str = '/api' , ** kwargs ) -> httpx .Response :
153
162
if requires_login :
154
163
await self .ensure_login ()
155
164
return await self .retry_on_401 (self ._delete , path , api_prefix , ** kwargs )
156
165
return await self ._delete (path , api_prefix , ** kwargs )
157
166
167
+ @retry_on_429
158
168
async def _delete (self , path , api_prefix , ** kwargs ) -> httpx .Response :
159
- response = await self .async_client .delete (api_prefix + path , ** kwargs )
160
- while response .status_code == 429 :
161
- await asyncio .sleep (SLEEP_TIME_ON_429 )
162
- response = await self .async_client .delete (api_prefix + path , ** kwargs )
163
- return response
169
+ return await self .async_client .delete (api_prefix + path , ** kwargs )
0 commit comments