Spaces:
Running
Running
| """ | |
| GovBridge India — Memory Guard Middleware (Sprint 18) | |
| Prevents progressive RAM bloat by: | |
| 1. Running gc.collect() after every request | |
| 2. Logging RSS memory usage for monitoring | |
| 3. Providing a /debug/memory endpoint for live inspection | |
| Target: Hugging Face Spaces (CPU Basic: 2 vCPU, 16GB RAM) | |
| """ | |
| import gc | |
| import os | |
| import psutil | |
| from starlette.middleware.base import BaseHTTPMiddleware | |
| from starlette.requests import Request | |
| from starlette.responses import Response, JSONResponse | |
| def get_memory_mb() -> float: | |
| """Get current process RSS in MB.""" | |
| process = psutil.Process(os.getpid()) | |
| return process.memory_info().rss / (1024 * 1024) | |
| class MemoryGuardMiddleware(BaseHTTPMiddleware): | |
| """ | |
| Post-request garbage collection middleware. | |
| CRITICAL DESIGN: Python's default GC thresholds (700, 10, 10) are | |
| tuned for short-lived scripts, not long-running ML servers. PyTorch | |
| tensors create circular references that the generational GC doesn't | |
| collect promptly. Forcing gc.collect() after every request ensures | |
| translation tensors are freed immediately. | |
| Performance impact: gc.collect() takes 1-5ms on this workload. | |
| Negligible vs. the 2-4s translation + inference latency. | |
| """ | |
| # Threshold in MB. If exceeded, log a warning. | |
| MEMORY_WARNING_THRESHOLD_MB = 12_000 # 12GB of 16GB | |
| async def dispatch(self, request: Request, call_next): | |
| response = await call_next(request) | |
| # Force garbage collection after every request | |
| collected = gc.collect() | |
| # Log memory state for monitoring (only on heavy endpoints) | |
| if request.url.path in ("/api/rag/query", "/webhook/whatsapp"): | |
| mem_mb = get_memory_mb() | |
| if mem_mb > self.MEMORY_WARNING_THRESHOLD_MB: | |
| print(f"🚨 MEMORY WARNING: {mem_mb:.0f}MB RSS (threshold: {self.MEMORY_WARNING_THRESHOLD_MB}MB)") | |
| elif collected > 0: | |
| print(f"🧹 GC freed {collected} objects | RSS: {mem_mb:.0f}MB") | |
| return response | |