加速成長分析指紋快取
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s

This commit is contained in:
OoO
2026-05-19 13:24:11 +08:00
parent 4a0a8bf75b
commit 1d3da03eee
5 changed files with 84 additions and 4 deletions

View File

@@ -9,6 +9,7 @@ older imports working and only owns growth-analysis and slow-query helpers.
import os
import pickle
import time
from datetime import datetime, timezone, timedelta
from pathlib import Path
from services.cache_manager import (
@@ -42,6 +43,8 @@ _GROWTH_ANALYSIS_CACHE = {
_GROWTH_CACHE_TTL = 1800 # 成長分析快取: 30 分鐘
_BASE_DIR = Path(__file__).resolve().parents[1]
_GROWTH_SHARED_CACHE_FILE = _BASE_DIR / "data" / "growth_analysis_cache.pkl"
_GROWTH_SOURCE_FINGERPRINT_CACHE = {}
_GROWTH_SOURCE_FINGERPRINT_TTL = 60
# ==========================================
# 慢查詢監控
@@ -89,6 +92,7 @@ def clear_growth_cache():
'timestamp': None,
'source_fingerprint': None,
}
_GROWTH_SOURCE_FINGERPRINT_CACHE.clear()
try:
if os.path.exists(_GROWTH_SHARED_CACHE_FILE):
os.remove(_GROWTH_SHARED_CACHE_FILE)
@@ -128,6 +132,35 @@ def get_growth_cache():
return _GROWTH_ANALYSIS_CACHE
def get_growth_source_fingerprint_cache(cache_key):
"""讀取短 TTL source fingerprint避免每次命中頁面快取仍掃大表 COUNT。"""
entry = _GROWTH_SOURCE_FINGERPRINT_CACHE.get(cache_key)
if not entry:
return None
if time.time() - entry.get('time', 0) >= _GROWTH_SOURCE_FINGERPRINT_TTL:
_GROWTH_SOURCE_FINGERPRINT_CACHE.pop(cache_key, None)
return None
return entry.get('fingerprint')
def set_growth_source_fingerprint_cache(cache_key, fingerprint):
"""寫入 source fingerprint 短快取None 不快取,維持 fail-open。"""
if fingerprint is None:
return
_GROWTH_SOURCE_FINGERPRINT_CACHE[cache_key] = {
'fingerprint': fingerprint,
'time': time.time(),
}
def clear_growth_source_fingerprint_cache(cache_key=None):
"""清除 source fingerprint 快取;匯入流程會呼叫 clear_growth_cache 一併處理。"""
if cache_key is None:
_GROWTH_SOURCE_FINGERPRINT_CACHE.clear()
else:
_GROWTH_SOURCE_FINGERPRINT_CACHE.pop(cache_key, None)
def _is_growth_payload_valid(payload, source_fingerprint=None):
if not payload:
return False