All Stories
3-5-cache-invalidation-on-game-status-changeDoneEpic 3.5
Story 3.5: Cache Invalidation on Game Status Change
Status: done
Tasks
- Task 1: Create CacheInvalidationService (AC: 1, 2, 3, 5, 8)
- 1.1 Create `server/app/services/cache_invalidation_service.py`
- 1.2 Implement `invalidate_game_cache(game_id, reason)` method
- 1.3 Define invalidation patterns: `odds:{status}:{game_id}` for all status types
- 1.4 Add reason enum: `STATUS_CHANGE`, `ODDS_MOVEMENT`, `CANCELLED`, `POSTPONED`, `MANUAL`, `SIDEBAR_REFRESH`
- 1.5 Implement batch key deletion using existing `delete_cached()` and `clear_pattern()`
- Task 3: Service-Layer Invalidation (AC: 4, 1) - ADAPTED
- 3.1 Integrated invalidation with `GameStatusClassifier.classify_and_cache()` method
- 3.2 Status changes detected during classification trigger invalidation
- 3.3 Call `CacheInvalidationService.invalidate_on_status_change()` when status differs
- Task 4: Sidebar Cache Integration (AC: 6)
- 4.1 Implemented `invalidate_sidebar_cache()` method in CacheInvalidationService
- 4.2 Supports selective invalidation by sport_id/league_id
- 4.3 Uses pattern-based deletion: `sidebar:{sport_id}:{league_id}:*`
- Task 5: Odds Movement Detection (AC: 2)
- 5.1 Add odds comparison logic in `invalidate_on_odds_movement()`
- 5.2 Calculate percentage change: `abs(new - old) / abs(old)`
- 5.3 Trigger invalidation if change >10% on any line
- 5.4 Returns 0 (no invalidation) for minor movements
- 6.1 Deferred to WebSocket story - infrastructure not yet implemented
- Task 7: Monitoring & Metrics (AC: 8, 9)
- 7.1 Add invalidation counters: `total_invalidations`, `keys_deleted`, `by_reason`
- 7.2 Track invalidations per minute with alert threshold (100/min)
- 7.3 Added `/api/v1/shared/cache/invalidation/stats` endpoint
- 7.4 Added `/api/v1/shared/cache/invalidation/events` for recent events
- 7.5 Log warning when invalidation rate exceeds threshold
- Task 8: Production-Safe Key Tracking (AC: 10)
- 8.1 Implement cache key registry: `register_cache_key()` adds to Redis SET
- 8.2 On invalidation, `_invalidate_from_registry()` retrieves keys from set
- 8.3 Clean up registry set after invalidation
- 8.4 Add TTL to registry set (24hr) matching max cache TTL
- Task 9: Testing & Validation (AC: 1-10)
- 9.1 Unit test: CacheInvalidationService with mock Redis (24 tests)
- 9.2 Test status transitions via classify_and_cache integration
- 9.3 Test odds movement threshold (below 10% no invalidate, above 10% invalidates)
- 9.4 Test sidebar invalidation (full and selective patterns)
- 9.5 Test alert threshold and rate calculation
- 9.6 Test key registry pattern
Progress
Tasks7/7
Acceptance Criteria0
Total Tasks7