All Stories
2-2-1-request-coalescingDoneEpic 2.2
Story 2.2.1: Request Coalescing
Status: done
Tasks
- Task 1: Create RequestCoalescer class (AC: #1, #2, #3, #5)
- 1.1: Implement `RequestCoalescer` class in `server/app/core/request_coalescer.py`
- 1.2: Add `_pending: Dict[str, PendingRequest]` to track pending requests
- 1.3: Add `_lock: asyncio.Lock()` for thread-safe access to pending map
- 1.4: Implement `async def get_or_fetch(cache_key: str, fetch_fn: Callable) -> Any` method
- 1.5: Check if `cache_key` exists in `_pending` map - if yes, await existing future
- 1.6: If no existing task, create new `asyncio.Future()` and execute fetch
- 1.7: Clean up completed tasks from `_pending` map in finally block
- 1.8: Ensure response format is identical for coalesced vs direct requests
- Task 2: Integrate coalescer into Optic Odds service (AC: #5)
- 2.1: Add `get_request_coalescer()` singleton to `server/app/core/request_coalescer.py`
- 2.2: Updated `_fetch_with_coalescing()` in fixtures.py to use centralized coalescer
- 2.3: Cache keys generated from endpoint + query params (e.g., `fixtures:nfl:True:5`)
- 2.4: Applied to fixtures endpoint (`/optic-odds/fixtures/*`) via existing SWR pattern
- Task 3: Add metrics tracking (AC: #4)
- 3.1: Added `CoalescerStats` dataclass for metrics collection
- 3.2: Track `coalesced_requests` counter (increment when cache_key exists in map)
- 3.3: Track `api_calls_made` counter (increment when creating new task)
- 3.4: Calculate `hit_rate_percent = (coalesced_requests / total_requests) * 100`
- 3.5: Exposed metrics via `/health/coalescer` endpoint
- 3.6: Include additional metrics: avg_wait_time_ms, max_concurrent_waiters, pending_keys
- Task 4: Write unit tests (AC: #1, #2, #3)
- 4.1: Test concurrent requests with same cache key trigger only one fetch
- 4.2: Test all waiting requests receive identical response
- 4.3: Test cache key uniqueness (different params = different keys)
- 4.4: Test error propagation to all waiting requests
- 4.5: Test cleanup of in-flight tasks after completion
- 4.6: Test thundering herd prevention with 100 concurrent requests
- 4.7: Test response format consistency
- Created: `server/tests/unit/test_request_coalescer.py` (22 tests, all passing)
- Task 5: Write integration tests (AC: #4, #5)
- 5.1: Test coalescer health endpoint exists and returns valid structure
- 5.2: Test metrics fields are present in response
- 5.3: Test health status is valid (healthy/warning/degraded)
- 5.4: Test concurrent fixture requests share API calls
- 5.5: Test max_wait_seconds is configured to 5s per acceptance criteria
- 5.6: Test /health/coalescer endpoint returns valid metrics
- Created: `server/tests/e2e/test_2_2_1_request_coalescing.py`
Progress
Tasks5/5
Acceptance Criteria0
Total Tasks5