Skip to content

Commit ac97b0a

Browse files
committed
Support retry in async client
This adds support for retry in the async client.
1 parent 02d7f79 commit ac97b0a

File tree

2 files changed

+66
-8
lines changed
  • .generator/src/generator/templates
  • src/datadog_api_client

2 files changed

+66
-8
lines changed

.generator/src/generator/templates/rest.j2

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ from {{ package }}.exceptions import (
2121
logger = logging.getLogger(__name__)
2222

2323

24+
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 500, 501, 502, 503, 504, 505, 506, 507, 509, 510, 511])
25+
26+
2427
class ClientRetry(urllib3.util.Retry):
25-
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 500, 501, 502, 503, 504, 505, 506, 507, 509, 510, 511])
28+
RETRY_AFTER_STATUS_CODES = RETRY_AFTER_STATUS_CODES
2629
DEFAULT_ALLOWED_METHODS = frozenset(["GET", "PUT", "DELETE", "POST", "PATCH"])
2730

2831
def get_retry_after(self, response):
@@ -235,6 +238,17 @@ class AsyncRESTClientObject:
235238
if configuration.proxy:
236239
proxy = aiosonic.Proxy(configuration.proxy, configuration.proxy_headers)
237240
self._client = aiosonic.HTTPClient(proxy=proxy)
241+
self._configuration = configuration
242+
243+
def _retry(self, response, counter):
244+
if (not self._configuration.enable_retry
245+
or counter >= self._configuration.max_retries
246+
or response.status_code not in RETRY_AFTER_STATUS_CODES):
247+
return 0
248+
retry_after = response.headers.get("X-Ratelimit-Reset")
249+
if retry_after is None:
250+
return self._configuration.retry_backoff_factor * (2 ** (counter))
251+
return int(retry_after)
238252

239253
async def request(
240254
self,
@@ -285,9 +299,23 @@ class AsyncRESTClientObject:
285299
request_body = compress.compress(request_body.encode("utf-8")) + compress.flush()
286300
elif headers.get("Content-Encoding") == "deflate":
287301
request_body = zlib.compress(request_body.encode("utf-8"))
288-
response = await self._client.request(
289-
url, method, headers, query_params, request_body, timeouts=request_timeout
290-
)
302+
elif headers.get("Content-Encoding") == "zstd1":
303+
import zstandard as zstd
304+
305+
compressor = zstd.ZstdCompressor()
306+
request_body = compressor.compress(request_body.encode("utf-8"))
307+
counter = 0
308+
while True:
309+
response = await self._client.request(
310+
url, method, headers, query_params, request_body, timeouts=request_timeout
311+
)
312+
retry = self._retry(response, counter)
313+
if not retry:
314+
break
315+
import asyncio
316+
317+
await asyncio.sleep(retry)
318+
counter += 1
291319

292320
if not 200 <= response.status_code <= 299:
293321
data = b""

src/datadog_api_client/rest.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@
2323
logger = logging.getLogger(__name__)
2424

2525

26+
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 500, 501, 502, 503, 504, 505, 506, 507, 509, 510, 511])
27+
28+
2629
class ClientRetry(urllib3.util.Retry):
27-
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 500, 501, 502, 503, 504, 505, 506, 507, 509, 510, 511])
30+
RETRY_AFTER_STATUS_CODES = RETRY_AFTER_STATUS_CODES
2831
DEFAULT_ALLOWED_METHODS = frozenset(["GET", "PUT", "DELETE", "POST", "PATCH"])
2932

3033
def get_retry_after(self, response):
@@ -237,6 +240,19 @@ def __init__(self, configuration):
237240
if configuration.proxy:
238241
proxy = aiosonic.Proxy(configuration.proxy, configuration.proxy_headers)
239242
self._client = aiosonic.HTTPClient(proxy=proxy)
243+
self._configuration = configuration
244+
245+
def _retry(self, response, counter):
246+
if (
247+
not self._configuration.enable_retry
248+
or counter >= self._configuration.max_retries
249+
or response.status_code not in RETRY_AFTER_STATUS_CODES
250+
):
251+
return 0
252+
retry_after = response.headers.get("X-Ratelimit-Reset")
253+
if retry_after is None:
254+
return self._configuration.retry_backoff_factor * (2 ** (counter))
255+
return int(retry_after)
240256

241257
async def request(
242258
self,
@@ -287,9 +303,23 @@ async def request(
287303
request_body = compress.compress(request_body.encode("utf-8")) + compress.flush()
288304
elif headers.get("Content-Encoding") == "deflate":
289305
request_body = zlib.compress(request_body.encode("utf-8"))
290-
response = await self._client.request(
291-
url, method, headers, query_params, request_body, timeouts=request_timeout
292-
)
306+
elif headers.get("Content-Encoding") == "zstd1":
307+
import zstandard as zstd
308+
309+
compressor = zstd.ZstdCompressor()
310+
request_body = compressor.compress(request_body.encode("utf-8"))
311+
counter = 0
312+
while True:
313+
response = await self._client.request(
314+
url, method, headers, query_params, request_body, timeouts=request_timeout
315+
)
316+
retry = self._retry(response, counter)
317+
if not retry:
318+
break
319+
import asyncio
320+
321+
await asyncio.sleep(retry)
322+
counter += 1
293323

294324
if not 200 <= response.status_code <= 299:
295325
data = b""

0 commit comments

Comments
 (0)