WAGERBABE DOCS
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