From 4c4efd614a2c6c56c2a54efbe8eda2bc6f558f4d Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Mon, 23 Feb 2026 17:21:57 -0500 Subject: [PATCH] fix(odds): use update_interval as cache TTL and fix live game cache refresh (#268) * fix(odds): use 2-minute cache for live games instead of 30 minutes Live game odds were being cached for 30 minutes because the cache key didn't trigger the odds_live cache strategy. Added is_live parameter to get_odds() and include 'live' suffix in cache key for live games, which triggers the existing odds_live strategy (2 min TTL). Co-Authored-By: Claude Opus 4.5 * fix(base-odds): Use interval as TTL for cache operations - Pass interval variable as TTL to cache_manager.set() calls - Ensures cache expires after update interval, preventing stale data - Removes dead code by actually using the computed interval value * refactor(base-odds): Remove is_live parameter from base class for modularity - Remove is_live parameter from get_odds() method signature - Remove cache key modification logic from base class - Remove is_live handling from get_odds_for_games() - Keep base class minimal and generic for reuse by other plugins - Plugin-specific is_live logic moved to odds-ticker plugin override --------- Co-authored-by: Chuck Co-authored-by: Claude Opus 4.5 --- src/base_classes/sports.py | 3 ++- src/base_odds_manager.py | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/base_classes/sports.py b/src/base_classes/sports.py index 5dba8cf7..ed3bc018 100644 --- a/src/base_classes/sports.py +++ b/src/base_classes/sports.py @@ -415,7 +415,8 @@ class SportsCore(ABC): sport=self.sport, league=self.league, event_id=game['id'], - update_interval_seconds=update_interval + update_interval_seconds=update_interval, + is_live=is_live ) if odds_data: diff --git a/src/base_odds_manager.py b/src/base_odds_manager.py index 64d1cb10..ce57fcdd 100644 --- a/src/base_odds_manager.py +++ b/src/base_odds_manager.py @@ -84,7 +84,7 @@ class BaseOddsManager: except Exception as e: self.logger.warning(f"Failed to load BaseOddsManager configuration: {e}") - def get_odds(self, sport: str | None, league: str | None, event_id: str, + def get_odds(self, sport: str | None, league: str | None, event_id: str, update_interval_seconds: int = None) -> Optional[Dict[str, Any]]: """ Fetch odds data for a specific game. @@ -94,13 +94,13 @@ class BaseOddsManager: league: League name (e.g., 'nfl', 'nba') event_id: ESPN event ID update_interval_seconds: Override default update interval - + Returns: Dictionary containing odds data or None if unavailable """ if sport is None or league is None: raise ValueError("Sport and League cannot be None") - + # Use provided interval or default interval = update_interval_seconds or self.update_interval cache_key = f"odds_espn_{sport}_{league}_{event_id}" @@ -143,12 +143,12 @@ class BaseOddsManager: self.logger.debug("No odds data available for this game") if odds_data: - self.cache_manager.set(cache_key, odds_data) - self.logger.info(f"Saved odds data to cache for {cache_key}") + self.cache_manager.set(cache_key, odds_data, ttl=interval) + self.logger.info(f"Saved odds data to cache for {cache_key} with TTL {interval}s") else: self.logger.debug(f"No odds data available for {cache_key}") # Cache the fact that no odds are available to avoid repeated API calls - self.cache_manager.set(cache_key, {"no_odds": True}) + self.cache_manager.set(cache_key, {"no_odds": True}, ttl=interval) return odds_data @@ -208,34 +208,34 @@ class BaseOddsManager: def get_odds_for_games(self, games: List[Dict[str, Any]]) -> List[Dict[str, Any]]: """ Fetch odds for multiple games efficiently. - + Args: games: List of game dictionaries with sport, league, and id - + Returns: List of games with odds data added """ games_with_odds = [] - + for game in games: try: sport = game.get('sport') league = game.get('league') event_id = game.get('id') - + if sport and league and event_id: odds_data = self.get_odds(sport, league, event_id) game['odds'] = odds_data else: game['odds'] = None - + games_with_odds.append(game) - + except Exception as e: self.logger.error(f"Error fetching odds for game {game.get('id', 'unknown')}: {e}") game['odds'] = None games_with_odds.append(game) - + return games_with_odds def is_odds_available(self, odds_data: Optional[Dict[str, Any]]) -> bool: