Skip to content

Commit 8607f39

Browse files
authored
feat: retry with backoff (#5)
This makes the library more robust if there are network hiccups or if the API server does a timeout for other reasons. The backoff will sleep for [0.0s, 0.2s, 0.4s, ...] for up to five retries with the default settings.
1 parent 81e3c0a commit 8607f39

File tree

3 files changed

+66
-14
lines changed

3 files changed

+66
-14
lines changed

acrclient/client.py

+66-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
from typing import Any, Optional
1+
from __future__ import annotations
22

3-
from requests import get
3+
from typing import Any, Optional, Union
4+
5+
from requests import Session
6+
from requests.adapters import HTTPAdapter, Retry
47
from requests.auth import AuthBase
58
from requests.models import PreparedRequest, Response
69

@@ -21,22 +24,76 @@ def __call__(self, request: PreparedRequest) -> PreparedRequest:
2124
class Client:
2225
"""ACRCloud client to fetch metadata.
2326
24-
Args:
25-
bearer_token: The bearer token for ACRCloud.
27+
>>> bearer_token = "bearer-token"
28+
>>> config = Client.Config(retries= 5, backoff_factor= 0.1)
29+
>>> client = Client(bearer_token, config=config)
30+
31+
:param str bearer_token
32+
The bearer token for ACRCloud.
2633
"""
2734

28-
def __init__(self, bearer_token: str, base_url="https://eu-api-v2.acrcloud.com"):
29-
self.base_url = base_url
30-
self.auth = _Auth(bearer_token=bearer_token)
35+
class Config:
36+
"""Configuration for acrclient.
37+
38+
:param int retries
39+
Total number of retries to allow.
40+
41+
:param float backoff_factor
42+
A backoff factor to apply between attempts after the second try
43+
(most errors are resolved immediately by a second try without a
44+
delay). urllib3 will sleep for::
45+
{backoff factor} * (2 ** ({number of total retries} - 1))
46+
seconds. If the backoff_factor is 0.1, then :func:`Retry.sleep` will sleep
47+
for [0.0s, 0.2s, 0.4s, ...] between retries. It will never be longer
48+
than `backoff_max`.
49+
By default, backoff is set to 0.1.
50+
"""
51+
52+
def __init__(
53+
self,
54+
retries: Union[bool | int | None] = 5,
55+
backoff_factor: float = 0.1,
56+
):
57+
self._retries: Union[bool | int | None] = retries
58+
self._backoff_factor: float = backoff_factor
59+
60+
@property
61+
def retries(self):
62+
return self._retries
63+
64+
@property
65+
def backoff_factor(self):
66+
return self._backoff_factor
67+
68+
def __init__(
69+
self,
70+
bearer_token: str,
71+
base_url: str = "https://eu-api-v2.acrcloud.com",
72+
config: Optional[Config] = None,
73+
):
74+
self.base_url: str = base_url
75+
76+
self._config: Optional[Client.Config] = config or Client.Config()
77+
self._auth: _Auth = _Auth(bearer_token=bearer_token)
78+
self._session = Session()
79+
self._session.mount(
80+
"https://",
81+
HTTPAdapter(
82+
max_retries=Retry(
83+
total=self._config.retries,
84+
backoff_factor=self._config.backoff_factor,
85+
)
86+
),
87+
)
3188

3289
def get(self, path: str, params: Any = None, **kwargs) -> Response:
3390
"""Fetch JSON data from ACRCloud API with set Access Key param."""
3491
url = f"{self.base_url}{path}"
3592
if not kwargs.get("timeout"):
36-
kwargs["timeout"] = 10
93+
kwargs["timeout"] = 60
3794

3895
# pylint: disable-next=missing-timeout
39-
response = get(url=url, auth=self.auth, params=params, **kwargs)
96+
response = self._session.get(url=url, auth=self._auth, params=params, **kwargs)
4097
response.raise_for_status()
4198
return response
4299

pyproject.toml

-4
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,8 @@ pytest-random-order = "^1.1.0"
3838

3939

4040
[tool.isort]
41-
line_length = 120
4241
profile = "black"
4342

44-
[tool.pylint.format]
45-
max-line-lenth = 120
46-
4743
[tool.pylint.messages_control]
4844
# C0114 = missing-module-docstring
4945
# C0116 = missing-function-docstring

tests/test_client.py

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
def test_client():
88
client = Client(_Auth("bearer-token"))
99
assert isinstance(client, Client)
10-
assert isinstance(client.auth, _Auth)
1110
assert client.base_url == "https://eu-api-v2.acrcloud.com"
1211

1312

0 commit comments

Comments
 (0)