#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 快取服務模組 集中管理所有快取變數和相關操作 """ from datetime import datetime, timezone, timedelta # 台北時區 TAIPEI_TZ = timezone(timedelta(hours=8)) # ========================================== # 業績分析快取 # ========================================== _SALES_DF_CACHE = {} _SALES_PROCESSED_CACHE = {} # 處理後資料快取 (二級快取) _SALES_OPTIONS_CACHE = {} # 下拉選單選項 (類別、品牌、廠商等) _SALES_ANALYSIS_RESULT_CACHE = {} # 過濾後的分析結果集 # 快取 TTL 設定 _SALES_CACHE_TTL = 3600 # 業績分析快取: 60 分鐘 _SALES_OPTIONS_TTL = 21600 # 選項快取: 6 小時 _SALES_RESULT_TTL = 3600 # 結果快取: 60 分鐘 # ========================================== # 商品看板快取 # ========================================== _DASHBOARD_DATA_CACHE = { 'consolidated_data': None, 'consolidated_timestamp': None, 'full_data': None, 'full_timestamp': None } _DASHBOARD_CACHE_TTL = 1800 # 商品看板快取: 30 分鐘 # ========================================== # 成長分析快取 # ========================================== _GROWTH_ANALYSIS_CACHE = { 'chart_data': None, 'kpi': None, 'timestamp': None } _GROWTH_CACHE_TTL = 1800 # 成長分析快取: 30 分鐘 # ========================================== # 慢查詢監控 # ========================================== _SLOW_QUERY_STATS = { 'total_queries': 0, 'slow_queries': 0, 'very_slow_queries': 0, 'total_query_time_ms': 0, 'last_slow_query': None, 'last_slow_query_time': None, } _SLOW_QUERY_THRESHOLD_MS = 1000 # 慢查詢閾值: 1秒 _VERY_SLOW_QUERY_THRESHOLD_MS = 5000 # 極慢查詢閾值: 5秒 def track_query_time(query_name, duration_ms): """追蹤查詢時間,更新慢查詢統計""" global _SLOW_QUERY_STATS _SLOW_QUERY_STATS['total_queries'] += 1 _SLOW_QUERY_STATS['total_query_time_ms'] += duration_ms if duration_ms >= _VERY_SLOW_QUERY_THRESHOLD_MS: _SLOW_QUERY_STATS['very_slow_queries'] += 1 _SLOW_QUERY_STATS['slow_queries'] += 1 _SLOW_QUERY_STATS['last_slow_query'] = query_name _SLOW_QUERY_STATS['last_slow_query_time'] = datetime.now(TAIPEI_TZ).isoformat() elif duration_ms >= _SLOW_QUERY_THRESHOLD_MS: _SLOW_QUERY_STATS['slow_queries'] += 1 _SLOW_QUERY_STATS['last_slow_query'] = query_name _SLOW_QUERY_STATS['last_slow_query_time'] = datetime.now(TAIPEI_TZ).isoformat() def get_slow_query_stats(): """取得慢查詢統計資料""" return _SLOW_QUERY_STATS.copy() def clear_sales_cache(): """清除業績分析快取""" global _SALES_DF_CACHE, _SALES_PROCESSED_CACHE, _SALES_OPTIONS_CACHE, _SALES_ANALYSIS_RESULT_CACHE _SALES_DF_CACHE.clear() _SALES_PROCESSED_CACHE.clear() _SALES_OPTIONS_CACHE.clear() _SALES_ANALYSIS_RESULT_CACHE.clear() def clear_dashboard_cache(): """清除商品看板快取""" global _DASHBOARD_DATA_CACHE _DASHBOARD_DATA_CACHE = { 'consolidated_data': None, 'consolidated_timestamp': None, 'full_data': None, 'full_timestamp': None } def clear_growth_cache(): """清除成長分析快取""" global _GROWTH_ANALYSIS_CACHE _GROWTH_ANALYSIS_CACHE = { 'chart_data': None, 'kpi': None, 'timestamp': None } def clear_all_cache(): """清除所有快取""" clear_sales_cache() clear_dashboard_cache() clear_growth_cache() def is_cache_valid(timestamp, ttl_seconds): """ 檢查快取是否有效 Args: timestamp: 快取時間戳記 ttl_seconds: 快取有效期(秒) Returns: bool: True 表示快取有效 """ if timestamp is None: return False now = datetime.now(TAIPEI_TZ) if timestamp.tzinfo is None: timestamp = timestamp.replace(tzinfo=TAIPEI_TZ) age = (now - timestamp).total_seconds() return age < ttl_seconds def get_growth_cache(): """取得成長分析快取""" return _GROWTH_ANALYSIS_CACHE def set_growth_cache(chart_data, kpi): """設定成長分析快取""" global _GROWTH_ANALYSIS_CACHE _GROWTH_ANALYSIS_CACHE = { 'chart_data': chart_data, 'kpi': kpi, 'timestamp': datetime.now(TAIPEI_TZ) } def is_growth_cache_valid(): """檢查成長分析快取是否有效""" return is_cache_valid(_GROWTH_ANALYSIS_CACHE.get('timestamp'), _GROWTH_CACHE_TTL)