Skip to content

Commit

Permalink
🔧 Refactor utils.py to include retry logic and improve error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
shroominic committed May 7, 2024
1 parent 3cc3837 commit 73de41f
Showing 1 changed file with 60 additions and 9 deletions.
69 changes: 60 additions & 9 deletions src/codeboxapi/utils.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"""Utility functions for API requests"""

import json
from asyncio import sleep as asleep
from io import BytesIO
from time import sleep
from typing import Optional

import requests
from aiohttp import ClientResponse, ClientSession, FormData
from aiohttp import ClientError, ClientResponse, ClientSession, FormData
from aiohttp.payload import BytesIOPayload

from codeboxapi.config import settings
Expand Down Expand Up @@ -48,9 +50,13 @@ def handle_response(response: requests.Response):
response.headers["Content-Type"].split(";")[0], lambda r: r.content.decode()
)
if response.status_code != 200:
try:
json_body = response.json()
except Exception:
json_body = {"": response.text}
raise CodeBoxError(
http_status=response.status_code,
json_body=response.json(),
json_body=json_body,
headers=dict(response.headers.items()),
)
return handler(response)
Expand Down Expand Up @@ -100,13 +106,35 @@ def base_request(
endpoint: str,
body: Optional[dict] = None,
files: Optional[dict] = None,
retries: int = 3,
backoff_factor: float = 0.3,
) -> dict:
"""
Makes a request to the CodeBox API.
Makes a request to the CodeBox API with retry logic.
Args:
- method: HTTP method as a string.
- endpoint: API endpoint as a string.
- body: Optional dictionary containing the JSON body.
- files: Optional dictionary containing file data.
- retries: Maximum number of retries on failure.
- backoff_factor: Multiplier for delay between retries (exponential backoff).
Returns:
- A dictionary response from the API.
"""
request_data = build_request_data(method, endpoint, body, files)
response = requests.request(**request_data, timeout=270)
return handle_response(response)
for attempt in range(retries):
try:
response = requests.request(**request_data, timeout=270)
return handle_response(response)
except requests.RequestException as e:
if attempt < retries - 1:
sleep_time = backoff_factor * (2**attempt)
sleep(sleep_time)
else:
raise e
raise CodeBoxError(http_status=500, json_body={"error": "Max retries exceeded"})


async def abase_request(
Expand All @@ -115,9 +143,23 @@ async def abase_request(
endpoint: str,
body: Optional[dict] = None,
files: Optional[dict] = None,
retries: int = 3,
backoff_factor: float = 0.3,
) -> dict:
"""
Makes an asynchronous request to the CodeBox API.
Makes an asynchronous request to the CodeBox API with retry functionality.
Args:
- session: The aiohttp ClientSession.
- method: HTTP method as a string.
- endpoint: API endpoint as a string.
- body: Optional dictionary containing the JSON body.
- files: Optional dictionary containing file data.
- retries: Maximum number of retries on failure.
- backoff_factor: Multiplier for delay between retries (exponential backoff).
Returns:
- A dictionary response from the API.
"""
request_data = build_request_data(method, endpoint, body, files)
if files is not None:
Expand All @@ -133,11 +175,20 @@ async def abase_request(
request_data.pop("files")
request_data.pop("json")
request_data["data"] = data
response = await session.request(**request_data)
else:
request_data.pop("files")
response = await session.request(**request_data)
return await handle_response_async(response)

for attempt in range(retries):
try:
response = await session.request(**request_data)
return await handle_response_async(response)
except ClientError as e:
if attempt < retries - 1:
sleep_time = backoff_factor * (2**attempt)
await asleep(sleep_time)
else:
raise e
raise CodeBoxError(http_status=500, json_body={"error": "Max retries exceeded"})


def set_api_key(api_key: str) -> None:
Expand Down

0 comments on commit 73de41f

Please sign in to comment.