mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 13:02:59 +00:00
Feature/background season data (#46)
* Fix NCAAFB ranking display issue - Remove duplicate ranking system that was drawing rankings behind team logos - Old system (_get_rank) was drawing rankings at top of logos - New system (_fetch_team_rankings) correctly draws rankings in bottom corners - Remove old ranking calls from live, recent, and upcoming game drawing functions - Remove unnecessary _fetch_rankings() calls from update methods - Rankings now only appear in designated corner positions, not overlapping logos Fixes issue where team rankings/betting lines were being drawn behind team logos instead of replacing team records in the corners. * Add missing show_ranking and show_records options to NCAAFB web UI - Add show_ranking option to NCAAFB scoreboard config template - Add show_records and show_ranking toggle switches to NCAAFB web UI - Update JavaScript form collection to include new fields - Users can now control whether to show team records or rankings via web interface This completes the fix for NCAAFB ranking display - users can now enable show_ranking in the web UI to see AP Top 25 rankings instead of team records. * Implement Background Threading for Season Data Fetching Phase 1: Background Season Data Fetching - COMPLETED Key Features: - Created BackgroundDataService class with thread-safe operations - Implemented automatic retry logic with exponential backoff - Modified NFL manager to use background service - Added immediate partial data return for non-blocking display - Comprehensive logging and statistics tracking Performance Benefits: - Main display loop no longer blocked by API calls - Season data always fresh with background updates - Better user experience during data fetching Files Added/Modified: - src/background_data_service.py (NEW) - src/nfl_managers.py (updated) - config/config.template.json (updated) - test_background_service.py (NEW) - BACKGROUND_SERVICE_README.md (NEW) * Fix data validation issues in background service - Add comprehensive data structure validation in NFL managers - Handle malformed events gracefully with proper error logging - Validate cached data format and handle legacy formats - Add data validation in background service response parsing - Fix TypeError: string indices must be integers, not 'str' This fixes the error where events were being treated as strings instead of dictionaries, causing crashes in recent/upcoming games. * Phase 2: Apply Background Service to Major Sport Managers ✅ Applied background service support to: - NCAAFB Manager (College Football) - NBA Manager (Basketball) - NHL Manager (Hockey) - MLB Manager (Baseball) 🔧 Key Features Added: - Background service initialization for each sport - Configurable workers, timeouts, and retry settings - Graceful fallback when background service is disabled - Comprehensive logging for monitoring ⚙️ Configuration Updates: - Added background_service config section to NBA - Added background_service config section to NHL - Added background_service config section to NCAAFB - Each sport can independently enable/disable background service 📈 Performance Benefits: - Season data fetching no longer blocks display loops - Immediate response with cached/partial data - Background threads handle heavy API calls - Better responsiveness across all supported sports Next: Apply to remaining managers (MiLB, Soccer, etc.) * Fix Python compatibility issue in BackgroundDataService shutdown 🐛 Bug Fix: - Fixed TypeError in ThreadPoolExecutor.shutdown() for older Python versions - Added try/catch to handle timeout parameter compatibility - Fallback gracefully for Python < 3.9 that doesn't support timeout parameter 🔧 Technical Details: - ThreadPoolExecutor.shutdown(timeout=) was added in Python 3.9 - Older versions only support shutdown(wait=) - Added compatibility layer with proper error handling ✅ Result: - No more shutdown exceptions on older Python versions - Graceful degradation for different Python environments - Maintains full functionality on newer Python versions * Phase 2 Complete: Background Service Applied to All Sport Managers 🎉 MAJOR MILESTONE: Complete Background Service Rollout ✅ All Sport Managers Now Support Background Service: - MiLB Manager (Minor League Baseball) - Soccer Manager (Multiple leagues: Premier League, La Liga, etc.) - Leaderboard Manager (Multi-sport standings) - Odds Ticker Manager (Live betting odds) 🔧 Technical Implementation: - Background service initialization in all managers - Configurable workers, timeouts, and retry settings - Graceful fallback when background service is disabled - Comprehensive logging for monitoring and debugging - Thread-safe operations with proper error handling ⚙️ Configuration Support Added: - MiLB: background_service config section - Soccer: background_service config section - Leaderboard: background_service config section - Odds Ticker: background_service config section - Each manager can independently enable/disable background service 📈 Performance Benefits Achieved: - Non-blocking data fetching across ALL sport managers - Immediate response with cached/partial data - Background threads handle heavy API calls - Significantly improved responsiveness - Better user experience during data loading 🚀 Production Ready: - All major sport managers now support background threading - Comprehensive configuration options - Robust error handling and fallback mechanisms - Ready for production deployment Next: Phase 3 - Advanced features (priority queuing, analytics) * Update wiki submodule with Background Service documentation 📚 Wiki Documentation Added: - Complete Background Service Guide with architecture diagrams - Configuration examples and best practices - Performance benefits and troubleshooting guide - Migration guide and advanced features 🔧 Navigation Updates: - Added to sidebar under Technical section - Updated home page with performance section - Highlighted as NEW feature with ⚡ icon The wiki now includes comprehensive documentation for the new background threading system that improves performance across all sport managers. * Fix CacheManager constructor in test script 🐛 Bug Fix: - Fixed CacheManager initialization in test_background_service.py - CacheManager no longer takes config_manager parameter - Updated constructor call to match current implementation ✅ Result: - Test script now works with current CacheManager API - Background service testing can proceed without errors * Move test_background_service.py to test/ directory 📁 Organization Improvement: - Moved test_background_service.py from root to test/ directory - Updated import paths to work from new location - Fixed sys.path to correctly reference src/ directory - Updated imports to use relative paths 🔧 Technical Changes: - Changed sys.path from 'src' to '../src' (go up from test/) - Updated imports to remove 'src.' prefix - Maintains all functionality while improving project structure ✅ Benefits: - Better project organization - Test files properly grouped in test/ directory - Cleaner root directory structure - Follows standard Python project layout * Remove old test_background_service.py from root directory 📁 Cleanup: - Removed test_background_service.py from root directory - File has been moved to test/ directory for better organization - Maintains clean project structure * Fix NCAA FB team ranking display functionality - Add missing _fetch_team_rankings() calls to all update methods (live, recent, upcoming) - Add ranking display logic to live manager scorebug layout - Remove unused old _fetch_rankings() method and top_25_rankings variable - Rankings now properly display as #X format when show_ranking is enabled - Fixes non-functional ranking feature despite existing UI and configuration options
This commit is contained in:
183
test/test_background_service.py
Normal file
183
test/test_background_service.py
Normal file
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for Background Data Service with NFL Manager
|
||||
|
||||
This script tests the background threading functionality for NFL season data fetching.
|
||||
It demonstrates how the background service prevents blocking the main display loop.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
# Add src directory to path (go up one level from test/ to find src/)
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
|
||||
|
||||
from background_data_service import BackgroundDataService, get_background_service
|
||||
from cache_manager import CacheManager
|
||||
from config_manager import ConfigManager
|
||||
from nfl_managers import BaseNFLManager
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s.%(msecs)03d - %(levelname)s:%(name)s:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class MockDisplayManager:
|
||||
"""Mock display manager for testing."""
|
||||
def __init__(self):
|
||||
self.matrix = type('Matrix', (), {'width': 64, 'height': 32})()
|
||||
self.image = None
|
||||
|
||||
def update_display(self):
|
||||
pass
|
||||
|
||||
def format_date_with_ordinal(self, date):
|
||||
return date.strftime("%B %d")
|
||||
|
||||
def test_background_service():
|
||||
"""Test the background data service functionality."""
|
||||
logger.info("Starting Background Data Service Test")
|
||||
|
||||
# Initialize components
|
||||
config_manager = ConfigManager()
|
||||
cache_manager = CacheManager()
|
||||
|
||||
# Test configuration for NFL
|
||||
test_config = {
|
||||
"nfl_scoreboard": {
|
||||
"enabled": True,
|
||||
"test_mode": False,
|
||||
"background_service": {
|
||||
"enabled": True,
|
||||
"max_workers": 2,
|
||||
"request_timeout": 15,
|
||||
"max_retries": 2,
|
||||
"priority": 2
|
||||
},
|
||||
"favorite_teams": ["TB", "DAL"],
|
||||
"display_modes": {
|
||||
"nfl_live": True,
|
||||
"nfl_recent": True,
|
||||
"nfl_upcoming": True
|
||||
}
|
||||
},
|
||||
"timezone": "America/Chicago"
|
||||
}
|
||||
|
||||
# Initialize mock display manager
|
||||
display_manager = MockDisplayManager()
|
||||
|
||||
# Initialize NFL manager
|
||||
nfl_manager = BaseNFLManager(test_config, display_manager, cache_manager)
|
||||
|
||||
logger.info("NFL Manager initialized with background service")
|
||||
|
||||
# Test 1: Check if background service is enabled
|
||||
logger.info(f"Background service enabled: {nfl_manager.background_enabled}")
|
||||
if nfl_manager.background_service:
|
||||
logger.info(f"Background service workers: {nfl_manager.background_service.max_workers}")
|
||||
|
||||
# Test 2: Test data fetching with background service
|
||||
logger.info("Testing NFL data fetch with background service...")
|
||||
start_time = time.time()
|
||||
|
||||
# This should start a background fetch and return partial data immediately
|
||||
data = nfl_manager._fetch_nfl_api_data(use_cache=False)
|
||||
|
||||
fetch_time = time.time() - start_time
|
||||
logger.info(f"Initial fetch completed in {fetch_time:.2f} seconds")
|
||||
|
||||
if data and 'events' in data:
|
||||
logger.info(f"Received {len(data['events'])} events (partial data)")
|
||||
|
||||
# Show some sample events
|
||||
for i, event in enumerate(data['events'][:3]):
|
||||
logger.info(f" Event {i+1}: {event.get('id', 'N/A')}")
|
||||
else:
|
||||
logger.warning("No data received from initial fetch")
|
||||
|
||||
# Test 3: Wait for background fetch to complete
|
||||
logger.info("Waiting for background fetch to complete...")
|
||||
max_wait_time = 30 # 30 seconds max wait
|
||||
wait_start = time.time()
|
||||
|
||||
while time.time() - wait_start < max_wait_time:
|
||||
# Check if background fetch is complete
|
||||
current_year = datetime.now().year
|
||||
if current_year in nfl_manager.background_fetch_requests:
|
||||
request_id = nfl_manager.background_fetch_requests[current_year]
|
||||
result = nfl_manager.background_service.get_result(request_id)
|
||||
|
||||
if result and result.success:
|
||||
logger.info(f"Background fetch completed successfully in {result.fetch_time:.2f}s")
|
||||
logger.info(f"Full dataset contains {len(result.data)} events")
|
||||
break
|
||||
elif result and not result.success:
|
||||
logger.error(f"Background fetch failed: {result.error}")
|
||||
break
|
||||
else:
|
||||
# Check if we have cached data now
|
||||
cached_data = cache_manager.get(f"nfl_schedule_{current_year}")
|
||||
if cached_data:
|
||||
logger.info(f"Found cached data with {len(cached_data)} events")
|
||||
break
|
||||
|
||||
time.sleep(1)
|
||||
logger.info("Still waiting for background fetch...")
|
||||
|
||||
# Test 4: Test subsequent fetch (should use cache)
|
||||
logger.info("Testing subsequent fetch (should use cache)...")
|
||||
start_time = time.time()
|
||||
|
||||
data2 = nfl_manager._fetch_nfl_api_data(use_cache=True)
|
||||
|
||||
fetch_time2 = time.time() - start_time
|
||||
logger.info(f"Subsequent fetch completed in {fetch_time2:.2f} seconds")
|
||||
|
||||
if data2 and 'events' in data2:
|
||||
logger.info(f"Received {len(data2['events'])} events from cache")
|
||||
|
||||
# Test 5: Show service statistics
|
||||
if nfl_manager.background_service:
|
||||
stats = nfl_manager.background_service.get_statistics()
|
||||
logger.info("Background Service Statistics:")
|
||||
for key, value in stats.items():
|
||||
logger.info(f" {key}: {value}")
|
||||
|
||||
# Test 6: Test with background service disabled
|
||||
logger.info("Testing with background service disabled...")
|
||||
|
||||
test_config_disabled = test_config.copy()
|
||||
test_config_disabled["nfl_scoreboard"]["background_service"]["enabled"] = False
|
||||
|
||||
nfl_manager_disabled = BaseNFLManager(test_config_disabled, display_manager, cache_manager)
|
||||
logger.info(f"Background service enabled: {nfl_manager_disabled.background_enabled}")
|
||||
|
||||
start_time = time.time()
|
||||
data3 = nfl_manager_disabled._fetch_nfl_api_data(use_cache=False)
|
||||
fetch_time3 = time.time() - start_time
|
||||
|
||||
logger.info(f"Synchronous fetch completed in {fetch_time3:.2f} seconds")
|
||||
if data3 and 'events' in data3:
|
||||
logger.info(f"Received {len(data3['events'])} events synchronously")
|
||||
|
||||
logger.info("Background Data Service Test Complete!")
|
||||
|
||||
# Cleanup
|
||||
if nfl_manager.background_service:
|
||||
nfl_manager.background_service.shutdown(wait=True, timeout=10)
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
test_background_service()
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Test interrupted by user")
|
||||
except Exception as e:
|
||||
logger.error(f"Test failed with error: {e}", exc_info=True)
|
||||
Reference in New Issue
Block a user