Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 53 additions & 13 deletions app/apis/requests.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,68 @@
"""Async requests using aioHttp"""

import asyncio
import os

import aiohttp
from loguru import logger


class Requests:
# Perform async HTTP request
async def request(self, method, url, params=None, data=None, headers=None):
connector = aiohttp.TCPConnector(verify_ssl=False)
# Configurable behavior via env vars
# HTTP_TIMEOUT: total timeout in seconds (default 30)
# HTTP_SSL_VERIFY: "true" to enable SSL verification, otherwise disabled
timeout_total = float(os.getenv("HTTP_TIMEOUT", "30"))
ssl_verify_env = os.getenv("HTTP_SSL_VERIFY", "false").lower()
ssl_verify = ssl_verify_env in {"1", "true", "yes", "on"}

# Use ssl=None to respect verification, ssl=False to disable
connector = aiohttp.TCPConnector(ssl=None if ssl_verify else False)

try:
async with aiohttp.ClientSession(connector=connector) as session:
async with session.request(
method,
url,
params=params,
data=data,
headers=headers,
) as resp:
timeout = aiohttp.ClientTimeout(total=timeout_total)
async with aiohttp.ClientSession(
connector=connector, timeout=timeout
) as session:
# Basic retry for transient network/server errors
max_retries = 3
backoff = 1.0
last_err = None
for attempt in range(1, max_retries + 1):
try:
return await resp.json()

except aiohttp.client_exceptions.ContentTypeError:
return await resp.text()
async with session.request(
method,
url,
params=params,
data=data,
headers=headers,
) as resp:
# Raise for 4xx/5xx
resp.raise_for_status()
try:
return await resp.json()
except aiohttp.client_exceptions.ContentTypeError:
return await resp.text()
except (
aiohttp.ClientConnectionError,
aiohttp.ServerTimeoutError,
aiohttp.ClientResponseError,
) as e:
last_err = e
# Retry on 5xx or network issues
retryable_status = getattr(e, "status", None)
if attempt < max_retries and (
retryable_status is None
or 500 <= int(retryable_status) < 600
):
logger.warning(
f"HTTP transient error on attempt {attempt}/{max_retries}: {e}. Retrying in {backoff:.1f}s"
)
await asyncio.sleep(backoff)
backoff *= 2
continue
raise

except Exception as err:
logger.error(
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"1337x==2.0.1",
"aiohttp==3.11.9",
"aiohttp==3.12.14",
"aiosqlite==0.20.0",
"asyncpg==0.30.0",
"greenlet==3.1.1",
Expand Down
6 changes: 6 additions & 0 deletions sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ START_ADS_MESSAGE=
SENTRY_DSN=

ENVIRONMENT=local

# HTTP client configuration
# Total timeout in seconds for outgoing requests (default 30)
HTTP_TIMEOUT=30
# Set to "true" to enable SSL verification, otherwise disabled
HTTP_SSL_VERIFY=false
Loading