Skip to content

Commit c6a0dfb

Browse files
authored
Implement retries for authorization code (#183)
* Implement retry for get_token_cache. * Add httpx.ProxyError as an exception that warrants retry. * Retry on parent class httpx.NetworkError rather than httpx.ConnectError, to catch some of the other network-realted exceptions. --------- Co-authored-by: Raymond Wiker <rayw@equinor.com>
1 parent cc02044 commit c6a0dfb

2 files changed

Lines changed: 94 additions & 1 deletion

File tree

src/sumo/wrapper/_auth_provider.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@
77
import jwt
88
import time
99
from azure.identity import ManagedIdentityCredential
10+
import tenacity as tn
11+
from ._retry_strategy import _log_retry_info, _return_last_value
1012

1113
from msal_extensions.persistence import FilePersistence
1214
from msal_extensions.token_cache import PersistedTokenCache
15+
import errno
16+
1317

1418
if not sys.platform.startswith("linux"):
1519
from msal_extensions import build_encrypted_persistence
@@ -19,13 +23,29 @@ def scope_for_resource(resource_id):
1923
return f"{resource_id}/.default"
2024

2125

26+
def _maybe_nfs_exception(exception):
27+
return isinstance(exception, OSError) and (
28+
exception.errno in (errno.EAGAIN, errno.ESTALE)
29+
)
30+
31+
2232
class AuthProvider:
2333
def __init__(self, resource_id):
2434
self._resource_id = resource_id
2535
self._scope = scope_for_resource(resource_id)
2636
self._app = None
2737
return
2838

39+
@tn.retry(
40+
retry=tn.retry_if_exception(_maybe_nfs_exception),
41+
stop=tn.stop_after_attempt(6),
42+
wait=(
43+
tn.wait_exponential(multiplier=0.5, exp_base=2)
44+
+ tn.wait_random_exponential(multiplier=0.5, exp_base=2)
45+
),
46+
retry_error_callback=_return_last_value,
47+
before_sleep=_log_retry_info,
48+
)
2949
def get_token(self):
3050
accounts = self._app.get_accounts()
3151
if len(accounts) == 0:
@@ -77,6 +97,16 @@ def get_token_path(resource_id, suffix):
7797
)
7898

7999

100+
@tn.retry(
101+
retry=tn.retry_if_exception(_maybe_nfs_exception),
102+
stop=tn.stop_after_attempt(6),
103+
wait=(
104+
tn.wait_exponential(multiplier=0.5, exp_base=2)
105+
+ tn.wait_random_exponential(multiplier=0.5, exp_base=2)
106+
),
107+
retry_error_callback=_return_last_value,
108+
before_sleep=_log_retry_info,
109+
)
80110
def get_token_cache(resource_id, suffix):
81111
# https://github.com/AzureAD/microsoft-authentication-extensions-\
82112
# for-python
@@ -110,6 +140,16 @@ def get_token_cache(resource_id, suffix):
110140
return cache
111141

112142

143+
@tn.retry(
144+
retry=tn.retry_if_exception(_maybe_nfs_exception),
145+
stop=tn.stop_after_attempt(6),
146+
wait=(
147+
tn.wait_exponential(multiplier=0.5, exp_base=2)
148+
+ tn.wait_random_exponential(multiplier=0.5, exp_base=2)
149+
),
150+
retry_error_callback=_return_last_value,
151+
before_sleep=_log_retry_info,
152+
)
113153
def protect_token_cache(resource_id, suffix):
114154
token_path = get_token_path(resource_id, suffix)
115155

@@ -143,6 +183,16 @@ def __init__(self, client_id, authority, resource_id):
143183
pass
144184
return
145185

186+
@tn.retry(
187+
retry=tn.retry_if_exception(_maybe_nfs_exception),
188+
stop=tn.stop_after_attempt(6),
189+
wait=(
190+
tn.wait_exponential(multiplier=0.5, exp_base=2)
191+
+ tn.wait_random_exponential(multiplier=0.5, exp_base=2)
192+
),
193+
retry_error_callback=_return_last_value,
194+
before_sleep=_log_retry_info,
195+
)
146196
def login(self):
147197
scopes = [self._scope + " offline_access"]
148198
login_timeout_minutes = 7
@@ -200,6 +250,16 @@ def __init__(self, client_id, authority, resource_id):
200250
pass
201251
return
202252

253+
@tn.retry(
254+
retry=tn.retry_if_exception(_maybe_nfs_exception),
255+
stop=tn.stop_after_attempt(6),
256+
wait=(
257+
tn.wait_exponential(multiplier=0.5, exp_base=2)
258+
+ tn.wait_random_exponential(multiplier=0.5, exp_base=2)
259+
),
260+
retry_error_callback=_return_last_value,
261+
before_sleep=_log_retry_info,
262+
)
203263
def login(self):
204264
flow = self._app.initiate_device_flow([self._scope])
205265

@@ -232,13 +292,33 @@ def __init__(self, resource_id):
232292
self._scope = scope_for_resource(resource_id)
233293
return
234294

295+
@tn.retry(
296+
retry=tn.retry_if_exception(_maybe_nfs_exception),
297+
stop=tn.stop_after_attempt(6),
298+
wait=(
299+
tn.wait_exponential(multiplier=0.5, exp_base=2)
300+
+ tn.wait_random_exponential(multiplier=0.5, exp_base=2)
301+
),
302+
retry_error_callback=_return_last_value,
303+
before_sleep=_log_retry_info,
304+
)
235305
def get_token(self):
236306
return self._app.get_token(self._scope).token
237307

238308
pass
239309

240310

241311
class AuthProviderSumoToken(AuthProvider):
312+
@tn.retry(
313+
retry=tn.retry_if_exception(_maybe_nfs_exception),
314+
stop=tn.stop_after_attempt(6),
315+
wait=(
316+
tn.wait_exponential(multiplier=0.5, exp_base=2)
317+
+ tn.wait_random_exponential(multiplier=0.5, exp_base=2)
318+
),
319+
retry_error_callback=_return_last_value,
320+
before_sleep=_log_retry_info,
321+
)
242322
def __init__(self, resource_id):
243323
protect_token_cache(resource_id, ".sharedkey")
244324
token_path = get_token_path(resource_id, ".sharedkey")
@@ -253,6 +333,16 @@ def get_authorization(self):
253333
return {"X-SUMO-Token": self._token}
254334

255335

336+
@tn.retry(
337+
retry=tn.retry_if_exception(_maybe_nfs_exception),
338+
stop=tn.stop_after_attempt(6),
339+
wait=(
340+
tn.wait_exponential(multiplier=0.5, exp_base=2)
341+
+ tn.wait_random_exponential(multiplier=0.5, exp_base=2)
342+
),
343+
retry_error_callback=_return_last_value,
344+
before_sleep=_log_retry_info,
345+
)
256346
def get_auth_provider(
257347
client_id,
258348
authority,

src/sumo/wrapper/_retry_strategy.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ def _log_retry_info(retry_state):
1717

1818
# Define the conditions for retrying based on exception types
1919
def _is_retryable_exception(exception):
20-
return isinstance(exception, (httpx.TimeoutException, httpx.ConnectError))
20+
return isinstance(
21+
exception,
22+
(httpx.TimeoutException, httpx.NetworkError, httpx.ProxyError),
23+
)
2124

2225

2326
# Define the conditions for retrying based on HTTP status codes

0 commit comments

Comments
 (0)