From ed90654bf28a9733492906d6458746daae0e7e26 Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Mon, 23 Feb 2026 11:54:34 -0500 Subject: [PATCH] fix(cache): move odds key check before live/scoreboard in get_data_type_from_key (#256) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(cache): move odds key check before live/scoreboard check in get_data_type_from_key Cache keys like odds_espn_nba_game_123_live contain 'live', so they were matched by the generic ['live', 'current', 'scoreboard'] branch (sports_live, 30s TTL) before the 'odds' branch was ever reached. This caused live odds to expire every 30 seconds instead of every 120 seconds, hitting the ESPN odds API 4x more often than intended and risking rate-limiting. Fix: move the 'odds' check above the 'live'/'current'/'scoreboard' check so the more-specific prefix wins. No regressions: pure live_*/scoreboard_* keys (without 'odds') still route to sports_live. Co-Authored-By: Claude Sonnet 4.6 * fix(cache): remove dead soccer branch in get_data_type_from_key The inner `if 'soccer' in key_lower: return 'sports_live'` branch was dead code — both the soccer and non-soccer paths returned the same 'sports_live' value. Collapse to a single return statement. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Chuck Co-authored-by: Claude Sonnet 4.6 --- src/cache/cache_strategy.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/cache/cache_strategy.py b/src/cache/cache_strategy.py index c2f5bb88..32266835 100644 --- a/src/cache/cache_strategy.py +++ b/src/cache/cache_strategy.py @@ -194,33 +194,34 @@ class CacheStrategy: """ key_lower = key.lower() - # Live sports data + # Odds data — checked FIRST because odds keys may also contain 'live'/'current' + # (e.g. odds_espn_nba_game_123_live). The odds TTL (120s for live, 1800s for + # upcoming) must win over the generic sports_live TTL (30s) to avoid hitting + # the ESPN odds API every 30 seconds per game. + if 'odds' in key_lower: + # For live games, use shorter cache; for upcoming games, use longer cache + if any(x in key_lower for x in ['live', 'current']): + return 'odds_live' # Live odds change more frequently (120s TTL) + return 'odds' # Regular odds for upcoming games (1800s TTL) + + # Live sports data (only reached if key does NOT contain 'odds') if any(x in key_lower for x in ['live', 'current', 'scoreboard']): - if 'soccer' in key_lower: - return 'sports_live' # Soccer live data is very time-sensitive return 'sports_live' - + # Weather data if 'weather' in key_lower: return 'weather_current' - + # Market data if 'stock' in key_lower or 'crypto' in key_lower: if 'crypto' in key_lower: return 'crypto' return 'stocks' - + # News data if 'news' in key_lower: return 'news' - # Odds data - differentiate between live and upcoming games - if 'odds' in key_lower: - # For live games, use shorter cache; for upcoming games, use longer cache - if any(x in key_lower for x in ['live', 'current']): - return 'odds_live' # Live odds change more frequently - return 'odds' # Regular odds for upcoming games - # Sports schedules and team info if any(x in key_lower for x in ['schedule', 'team_map', 'league']): return 'sports_schedules'