Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make tenacity great again #170

Merged
merged 11 commits into from
Nov 9, 2023
12 changes: 6 additions & 6 deletions requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
msal>=1.18.0
msal>=1.24.1
msal-extensions>=1.0.0
PyYAML>=5.4
setuptools>=49.2.1
PyYAML>=6.0.1
setuptools>=68.0.0
pyjwt>=2.4.0
httpx>=0.25.0
tenacity>=8.2.3
azure-identity>=1.14.0
httpx>=0.24.1
tenacity>=8.2.2
azure-identity>=1.13.0
40 changes: 37 additions & 3 deletions src/sumo/wrapper/_blob_client.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,37 @@
import httpx

from ._decorators import raise_for_status, http_retry, raise_for_status_async
from ._decorators import (
is_retryable_exception,
is_retryable_status_code,
raise_for_status,
raise_for_status_async,
return_last_value,
)
from tenacity import (
retry,
retry_if_exception,
retry_if_result,
wait_exponential,
wait_random_exponential,
stop_after_attempt,
)


class BlobClient:
"""Upload blobs to blob store using pre-authorized URLs"""

@raise_for_status
@http_retry
@retry(
stop=stop_after_attempt(6),
retry=(
retry_if_exception(is_retryable_exception)
| retry_if_result(is_retryable_status_code)
),
wait=wait_exponential(multiplier=0.5)
+ wait_random_exponential(multiplier=0.5),
reraise=True,
retry_error_callback=return_last_value,
)
def upload_blob(self, blob: bytes, url: str):
"""Upload a blob.

Expand All @@ -26,7 +50,17 @@ def upload_blob(self, blob: bytes, url: str):
return response

@raise_for_status_async
@http_retry
@retry(
stop=stop_after_attempt(6),
retry=(
retry_if_exception(is_retryable_exception)
| retry_if_result(is_retryable_status_code)
),
wait=wait_exponential(multiplier=0.5)
+ wait_random_exponential(multiplier=0.5),
reraise=True,
retry_error_callback=return_last_value,
)
async def upload_blob_async(self, blob: bytes, url: str):
"""Upload a blob async.

Expand Down
4 changes: 4 additions & 0 deletions src/sumo/wrapper/_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ def is_retryable_status_code(response):
return response.status_code in [502, 503, 504]


def return_last_value(retry_state):
return retry_state.outcome.result()


def http_retry(func):
return tn.retry(
func,
Expand Down
112 changes: 103 additions & 9 deletions src/sumo/wrapper/sumo_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,21 @@
from ._auth_provider import get_auth_provider
from .config import APP_REGISTRATION, TENANT_ID, AUTHORITY_HOST_URI

from ._decorators import raise_for_status, http_retry, raise_for_status_async
from ._decorators import (
is_retryable_exception,
is_retryable_status_code,
raise_for_status,
raise_for_status_async,
return_last_value,
)
from tenacity import (
retry,
retry_if_exception,
retry_if_result,
wait_exponential,
wait_random_exponential,
stop_after_attempt,
)

logger = logging.getLogger("sumo.wrapper")

Expand Down Expand Up @@ -109,7 +123,17 @@ def blob_client(self) -> BlobClient:
return self._blob_client

@raise_for_status
@http_retry
@retry(
stop=stop_after_attempt(6),
retry=(
retry_if_exception(is_retryable_exception)
| retry_if_result(is_retryable_status_code)
),
wait=wait_exponential(multiplier=0.5)
+ wait_random_exponential(multiplier=0.5),
reraise=True,
retry_error_callback=return_last_value,
)
def get(self, path: str, params: dict = None) -> dict:
"""Performs a GET-request to the Sumo API.

Expand Down Expand Up @@ -156,7 +180,17 @@ def get(self, path: str, params: dict = None) -> dict:
return response

@raise_for_status
@http_retry
@retry(
stop=stop_after_attempt(6),
retry=(
retry_if_exception(is_retryable_exception)
| retry_if_result(is_retryable_status_code)
),
wait=wait_exponential(multiplier=0.5)
+ wait_random_exponential(multiplier=0.5),
reraise=True,
retry_error_callback=return_last_value,
)
def post(
self,
path: str,
Expand Down Expand Up @@ -229,7 +263,17 @@ def post(
return response

@raise_for_status
@http_retry
@retry(
stop=stop_after_attempt(6),
retry=(
retry_if_exception(is_retryable_exception)
| retry_if_result(is_retryable_status_code)
),
wait=wait_exponential(multiplier=0.5)
+ wait_random_exponential(multiplier=0.5),
reraise=True,
retry_error_callback=return_last_value,
)
def put(
self, path: str, blob: bytes = None, json: dict = None
) -> httpx.Response:
Expand Down Expand Up @@ -274,7 +318,17 @@ def put(
return response

@raise_for_status
@http_retry
@retry(
stop=stop_after_attempt(6),
retry=(
retry_if_exception(is_retryable_exception)
| retry_if_result(is_retryable_status_code)
),
wait=wait_exponential(multiplier=0.5)
+ wait_random_exponential(multiplier=0.5),
reraise=True,
retry_error_callback=return_last_value,
)
def delete(self, path: str, params: dict = None) -> dict:
"""Performs a DELETE-request to the Sumo API.

Expand Down Expand Up @@ -329,7 +383,17 @@ def getLogger(self, name):
return logger

@raise_for_status_async
@http_retry
@retry(
stop=stop_after_attempt(6),
retry=(
retry_if_exception(is_retryable_exception)
| retry_if_result(is_retryable_status_code)
),
wait=wait_exponential(multiplier=0.5)
+ wait_random_exponential(multiplier=0.5),
reraise=True,
retry_error_callback=return_last_value,
)
async def get_async(self, path: str, params: dict = None):
"""Performs an async GET-request to the Sumo API.

Expand Down Expand Up @@ -375,7 +439,17 @@ async def get_async(self, path: str, params: dict = None):
return response

@raise_for_status_async
@http_retry
@retry(
stop=stop_after_attempt(6),
retry=(
retry_if_exception(is_retryable_exception)
| retry_if_result(is_retryable_status_code)
),
wait=wait_exponential(multiplier=0.5)
+ wait_random_exponential(multiplier=0.5),
reraise=True,
retry_error_callback=return_last_value,
)
async def post_async(
self,
path: str,
Expand Down Expand Up @@ -451,7 +525,17 @@ async def post_async(
return response

@raise_for_status_async
@http_retry
@retry(
stop=stop_after_attempt(6),
retry=(
retry_if_exception(is_retryable_exception)
| retry_if_result(is_retryable_status_code)
),
wait=wait_exponential(multiplier=0.5)
+ wait_random_exponential(multiplier=0.5),
reraise=True,
retry_error_callback=return_last_value,
)
async def put_async(
self, path: str, blob: bytes = None, json: dict = None
) -> httpx.Response:
Expand Down Expand Up @@ -497,7 +581,17 @@ async def put_async(
return response

@raise_for_status_async
@http_retry
@retry(
stop=stop_after_attempt(6),
retry=(
retry_if_exception(is_retryable_exception)
| retry_if_result(is_retryable_status_code)
),
wait=wait_exponential(multiplier=0.5)
+ wait_random_exponential(multiplier=0.5),
reraise=True,
retry_error_callback=return_last_value,
)
async def delete_async(self, path: str, params: dict = None) -> dict:
"""Performs an async DELETE-request to the Sumo API.

Expand Down
Loading