避免商品看板冷快取阻塞
All checks were successful
CD Pipeline / deploy (push) Successful in 57s

This commit is contained in:
OoO
2026-05-13 12:10:34 +08:00
parent 0380d4c435
commit 86fc9c94c7
2 changed files with 43 additions and 1 deletions

View File

@@ -320,7 +320,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
# ==========================================
# 系統版本與路徑
# ==========================================
SYSTEM_VERSION = "V10.108"
SYSTEM_VERSION = "V10.109"
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
public_url = PUBLIC_URL # 用於模板顯示

View File

@@ -11,6 +11,7 @@ import math
import time
import hashlib
import pickle
import threading
from datetime import datetime, timezone, timedelta
from flask import Blueprint, request, render_template
from sqlalchemy import func, and_, text, bindparam
@@ -699,6 +700,10 @@ class FileLock:
_DASHBOARD_STALE_CACHE_MAX_AGE = 86400
_DASHBOARD_REFRESH_STATE = {
'started_at': 0,
'running': False,
}
def _new_dashboard_file_lock():
@@ -759,6 +764,38 @@ def _load_stale_full_dashboard_cache(now):
)
def _load_expired_shared_full_dashboard_cache(now):
"""只讀原 shared cache 檔的過期版本;不讀 clear_cache 後搬走的 stale 檔。"""
return _load_dashboard_cache_file(
now,
_DASHBOARD_SHARED_CACHE_FILE,
allow_stale=True,
label='過期共享',
)
def _trigger_dashboard_background_refresh(reason):
"""使用過期 shared cache 先回首頁時,背景補一次 fresh cache避免使用者卡 10s。"""
now_ts = time.time()
if _DASHBOARD_REFRESH_STATE['running']:
return
if now_ts - _DASHBOARD_REFRESH_STATE['started_at'] < 60:
return
def _refresh():
_DASHBOARD_REFRESH_STATE['running'] = True
try:
warm_full_dashboard_cache(reason=reason, force_rebuild=True)
except Exception as exc:
sys_log.warning(f"[Dashboard] [Cache] 背景預熱失敗: {exc}")
finally:
_DASHBOARD_REFRESH_STATE['running'] = False
_DASHBOARD_REFRESH_STATE['started_at'] = now_ts
thread = threading.Thread(target=_refresh, name='dashboard-cache-refresh', daemon=True)
thread.start()
def _write_shared_full_dashboard_cache(full_data):
"""原子寫入跨 worker 共享的商品看板深度快取。"""
cache_file = str(_DASHBOARD_SHARED_CACHE_FILE)
@@ -1031,6 +1068,11 @@ def get_full_dashboard_data(force_rebuild=False):
if shared_full_data:
return shared_full_data
expired_shared_data = None if force_rebuild else _load_expired_shared_full_dashboard_cache(now)
if expired_shared_data:
_trigger_dashboard_background_refresh('expired_shared_cache')
return expired_shared_data
# V-Opt: 使用檔案鎖避免多 gunicorn worker 同時計算
dashboard_lock = _new_dashboard_file_lock()
lock_acquired = dashboard_lock.acquire(blocking=False)