Really-amin's picture
Upload 136 files
48ae4e0 verified
"""
Async HTTP Client with Retry Logic
"""
import aiohttp
import asyncio
from typing import Dict, Optional, Any
from datetime import datetime
import logging
logger = logging.getLogger(__name__)
class APIClient:
def __init__(self, timeout: int = 10, max_retries: int = 3):
self.timeout = aiohttp.ClientTimeout(total=timeout)
self.max_retries = max_retries
self.session: Optional[aiohttp.ClientSession] = None
async def __aenter__(self):
self.session = aiohttp.ClientSession(timeout=self.timeout)
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
if self.session:
await self.session.close()
async def get(
self,
url: str,
headers: Optional[Dict] = None,
params: Optional[Dict] = None,
retry_count: int = 0
) -> Dict[str, Any]:
"""Make GET request with retry logic"""
start_time = datetime.utcnow()
try:
async with self.session.get(url, headers=headers, params=params) as response:
elapsed_ms = int((datetime.utcnow() - start_time).total_seconds() * 1000)
# Try to parse JSON response
try:
data = await response.json()
except:
data = await response.text()
return {
"success": response.status == 200,
"status_code": response.status,
"data": data,
"response_time_ms": elapsed_ms,
"error": None if response.status == 200 else {
"type": "http_error",
"message": f"HTTP {response.status}"
}
}
except asyncio.TimeoutError:
elapsed_ms = int((datetime.utcnow() - start_time).total_seconds() * 1000)
if retry_count < self.max_retries:
logger.warning(f"Timeout for {url}, retrying ({retry_count + 1}/{self.max_retries})")
await asyncio.sleep(2 ** retry_count) # Exponential backoff
return await self.get(url, headers, params, retry_count + 1)
return {
"success": False,
"status_code": 0,
"data": None,
"response_time_ms": elapsed_ms,
"error": {"type": "timeout", "message": "Request timeout"}
}
except aiohttp.ClientError as e:
elapsed_ms = int((datetime.utcnow() - start_time).total_seconds() * 1000)
return {
"success": False,
"status_code": 0,
"data": None,
"response_time_ms": elapsed_ms,
"error": {"type": "client_error", "message": str(e)}
}
except Exception as e:
elapsed_ms = int((datetime.utcnow() - start_time).total_seconds() * 1000)
logger.error(f"Unexpected error for {url}: {e}")
return {
"success": False,
"status_code": 0,
"data": None,
"response_time_ms": elapsed_ms,
"error": {"type": "unknown", "message": str(e)}
}