@@ -81,9 +81,11 @@ class Client:
8181 """Base Client for accessing the Hetzner Cloud API"""
8282
8383 _version = __version__
84- _retry_wait_time = 0.5
8584 __user_agent_prefix = "hcloud-python"
8685
86+ _retry_interval = 0.5
87+ _retry_max_retries = 5
88+
8789 def __init__ (
8890 self ,
8991 token : str ,
@@ -236,8 +238,6 @@ def request( # type: ignore[no-untyped-def]
236238 self ,
237239 method : str ,
238240 url : str ,
239- * ,
240- _tries : int = 1 ,
241241 ** kwargs ,
242242 ) -> dict :
243243 """Perform a request to the Hetzner Cloud API, wrapper around requests.request
@@ -247,50 +247,57 @@ def request( # type: ignore[no-untyped-def]
247247 :param timeout: Requests timeout in seconds
248248 :return: Response
249249 """
250- timeout = kwargs .pop ("timeout" , self ._requests_timeout )
251-
252- response = self ._requests_session .request (
253- method = method ,
254- url = self ._api_endpoint + url ,
255- headers = self ._get_headers (),
256- timeout = timeout ,
257- ** kwargs ,
258- )
259-
260- correlation_id = response .headers .get ("X-Correlation-Id" )
261- payload = {}
262- try :
263- if len (response .content ) > 0 :
264- payload = response .json ()
265- except (TypeError , ValueError ) as exc :
266- raise APIException (
267- code = response .status_code ,
268- message = response .reason ,
269- details = {"content" : response .content },
270- correlation_id = correlation_id ,
271- ) from exc
272-
273- if not response .ok :
274- if not payload or "error" not in payload :
250+ kwargs .setdefault ("timeout" , self ._requests_timeout )
251+
252+ url = self ._api_endpoint + url
253+ headers = self ._get_headers ()
254+
255+ retries = 0
256+ while True :
257+ response = self ._requests_session .request (
258+ method = method ,
259+ url = url ,
260+ headers = headers ,
261+ ** kwargs ,
262+ )
263+
264+ correlation_id = response .headers .get ("X-Correlation-Id" )
265+ payload = {}
266+ try :
267+ if len (response .content ) > 0 :
268+ payload = response .json ()
269+ except (TypeError , ValueError ) as exc :
275270 raise APIException (
276271 code = response .status_code ,
277272 message = response .reason ,
278273 details = {"content" : response .content },
279274 correlation_id = correlation_id ,
280- )
281-
282- error : dict = payload ["error" ]
275+ ) from exc
276+
277+ if not response .ok :
278+ if not payload or "error" not in payload :
279+ raise APIException (
280+ code = response .status_code ,
281+ message = response .reason ,
282+ details = {"content" : response .content },
283+ correlation_id = correlation_id ,
284+ )
285+
286+ error : dict = payload ["error" ]
287+
288+ if (
289+ error ["code" ] == "rate_limit_exceeded"
290+ and retries < self ._retry_max_retries
291+ ):
292+ time .sleep (retries * self ._retry_interval )
293+ retries += 1
294+ continue
283295
284- if error ["code" ] == "rate_limit_exceeded" and _tries < 5 :
285- time .sleep (_tries * self ._retry_wait_time )
286- _tries = _tries + 1
287- return self .request (method , url , _tries = _tries , ** kwargs )
288-
289- raise APIException (
290- code = error ["code" ],
291- message = error ["message" ],
292- details = error .get ("details" ),
293- correlation_id = correlation_id ,
294- )
296+ raise APIException (
297+ code = error ["code" ],
298+ message = error ["message" ],
299+ details = error .get ("details" ),
300+ correlation_id = correlation_id ,
301+ )
295302
296- return payload
303+ return payload
0 commit comments