Spaces:
Sleeping
Sleeping
File size: 7,640 Bytes
2978bba | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | # MorphGuard API Utilities
The `api_utils.py` module provides a sophisticated and resilient API client system with intelligent fallbacks for the MorphGuard application. This system is designed to handle network instability, server errors, and other common issues that can affect API communication.
## Key Features
- **Smart Request Queuing**: Prioritize critical requests to ensure they are processed first
- **Comprehensive Error Handling**: Detailed error diagnostics and classification
- **Intelligent Caching**: Stale-while-revalidate pattern for improved performance and resilience
- **Circuit Breaker Pattern**: Prevent cascading failures by failing fast when services are down
- **Extended Metrics and Monitoring**: Track performance and reliability metrics
- **Context-Aware Retry Strategies**: Intelligent backoff and jitter for optimal retry behavior
## Core Components
### 1. CircuitBreaker
Implements the circuit breaker pattern with three states:
- **CLOSED**: Normal operation, requests are sent normally
- **OPEN**: Circuit is tripped, all requests fail fast
- **HALF-OPEN**: Testing if the service has recovered
```python
# Example usage
cb = CircuitBreaker(failure_threshold=5, recovery_timeout=30.0)
if cb.allow_request():
try:
# Make request
result = make_api_call()
cb.record_success()
return result
except Exception as e:
cb.record_failure()
raise
else:
# Circuit is open, use fallback or fail fast
return fallback_data
```
### 2. StaleWhileRevalidateCache
Enhanced cache with stale-while-revalidate strategy:
- Returns stale data immediately while asynchronously fetching fresh data
- Reduces perceived latency and improves availability
- Supports custom TTL for different cache entries
```python
# Example usage
cache = StaleWhileRevalidateCache(cache_dir=".cache", stale_timeout=300.0)
# Define refresh callback
def refresh_data():
return fetch_fresh_data_from_api()
# Get data from cache, refresh in background if stale
data, is_fresh = cache.get("cache_key", refresh_callback=refresh_data)
# Use data immediately, even if stale
process_data(data)
```
### 3. APIUtils
The main API client with comprehensive resilience features:
- Configurable timeout, retries, and caching
- Circuit breaker pattern integration
- Priority-based request handling
- Detailed metrics and telemetry
```python
# Example usage
api = get_api_utils({
"base_url": "https://api.example.com",
"timeout": 30.0,
"retries": 3,
"cache_enabled": True
})
# Make a GET request with fallback
try:
result = api.get("/users", {"limit": 10}, {
"fallback": {"users": []},
"priority": "high"
})
process_users(result)
except Exception as e:
handle_error(e)
```
### 4. Decorator Functions
Utility decorators for applying resilience patterns to functions:
#### @retry
Automatically retry functions on failure:
```python
@retry(retries=3, retry_delay=1.0, fallback=default_value)
def fetch_user_data(user_id):
# This function will be retried up to 3 times if it fails
return api_call(f"/users/{user_id}")
```
#### @circuit_breaker
Apply circuit breaker pattern to functions:
```python
@circuit_breaker(failure_threshold=5, recovery_timeout=30.0, fallback=empty_list)
def search_products(query):
# This function will fail fast if it fails 5 times in a row
return api_call("/search", {"q": query})
```
#### @cacheable
Cache function results with TTL:
```python
@cacheable(ttl=60.0) # Cache for 1 minute
def get_product_categories():
# Results will be cached for 60 seconds
return api_call("/categories")
```
## Usage Example
Here's a complete example of using the API utilities:
```python
from src.api_utils import get_api_utils, retry, circuit_breaker, cacheable
# Configure API utilities
api = get_api_utils({
"base_url": "https://api.example.com",
"timeout": 30.0,
"retries": 3,
"cache_enabled": True
})
# Make a simple GET request
users = api.get("/users")
# POST request with error handling
try:
new_user = api.post("/users", {
"name": "John Doe",
"email": "john@example.com"
}, {
"critical": True, # High priority
"timeout": 60.0 # Longer timeout
})
print(f"Created user: {new_user}")
except Exception as e:
print(f"Failed to create user: {e}")
# Function with retry decorator
@retry(retries=3, retry_delay=1.0)
def fetch_user_data(user_id):
return api.get(f"/users/{user_id}")
# Function with circuit breaker
@circuit_breaker(failure_threshold=5, recovery_timeout=30.0)
def search_products(query):
return api.get("/search", {"q": query})
# Function with caching
@cacheable(ttl=60.0)
def get_product_categories():
return api.get("/categories")
# Get API metrics
metrics = api.get_metrics()
print(f"API metrics: {metrics}")
```
## Configuration Options
The API utilities can be configured with the following options:
| Option | Description | Default |
|--------|-------------|---------|
| `base_url` | Base URL for the API | `"http://localhost:5000/api"` |
| `timeout` | Request timeout in seconds | `30.0` |
| `retries` | Number of retries for failed requests | `3` |
| `retry_delay` | Base delay between retries in seconds | `1.0` |
| `retry_status_codes` | HTTP status codes to retry | `[408, 429, 500, 502, 503, 504]` |
| `cache_enabled` | Whether to enable caching | `True` |
| `cache_dir` | Directory to store cache files | `".mg_api_cache"` |
| `max_cache_entries` | Maximum number of in-memory cache entries | `100` |
| `stale_timeout` | Time in seconds before data is considered stale | `300.0` |
| `revalidation_timeout` | Maximum age for using stale data | `600.0` |
| `circuit_breaker_enabled` | Whether to enable circuit breaker | `True` |
| `failure_threshold` | Number of failures before circuit opens | `5` |
| `recovery_timeout` | Time in seconds before circuit half-opens | `30.0` |
| `priority_queue_enabled` | Whether to enable priority-based request queue | `True` |
| `max_queue_size` | Maximum size of request queue | `100` |
| `debug` | Whether to enable debug logging | `False` |
## Error Handling
The API utilities integrate with MorphGuard's error handling system to provide detailed error information:
```python
try:
result = api.get("/users/123")
except APIError as e:
if e.code == ErrorCode.NOT_FOUND:
print("User not found")
elif e.code == ErrorCode.UNAUTHORIZED:
print("Authentication required")
else:
print(f"API error: {e.message}")
except NetworkError as e:
print(f"Network error: {e.message}")
except Exception as e:
print(f"Unexpected error: {e}")
```
## Metrics and Monitoring
The API utilities track various metrics for monitoring:
```python
metrics = api.get_metrics()
print(f"Total requests: {metrics['total_requests']}")
print(f"Successful requests: {metrics['successful_requests']}")
print(f"Failed requests: {metrics['failed_requests']}")
print(f"Cached responses: {metrics['cached_responses']}")
print(f"Stale responses: {metrics['stale_responses']}")
print(f"Retries: {metrics['retries']}")
print(f"Circuit breaks: {metrics['circuit_breaks']}")
print(f"Average response time: {metrics['total_time'] / max(1, metrics['total_requests']):.2f}s")
```
## Testing
The API utilities include comprehensive unit tests to ensure reliability:
```bash
# Run all tests
python -m unittest tests.test_api_utils
# Run specific test class
python -m unittest tests.test_api_utils.TestCircuitBreaker
# Run specific test method
python -m unittest tests.test_api_utils.TestAPIUtils.test_circuit_breaker
``` |