修复数据链路 P0 瓶颈:缓存炸弹、Context 重渲染、LGBM 循环、TTL 不匹配

P0-1 sessionStorage 限制:
- writeCityDetailCacheBundle 只保留最近 3 个城市的详情
- 避免 3-10MB JSON 序列化阻塞主线程

P0-2 Context 拆分:
- 新增 CityDetailsContext 独立管理 cityDetailsByName 变更
- 新增 useCityDetails hook,只订阅详情的组件不再因 cities/proAccess 变化重渲染
- DashboardStoreContext 保持不变,向后兼容

P0-3 扫描终端 TTL:
- SCAN_TERMINAL_PAYLOAD_TTL_SEC 30s → 120s
- 匹配 ThreadPoolExecutor(4) x 60 城的实际重算耗时

P0-4 LGBM 循环依赖:
- LGBM 预测值不再作为 DEB 输入参与权重计算
- 保留为独立参考字段 lgbm.prediction 输出给前端展示
- 消除 DEB → LGBM 训练 → DEB 的循环

新增 docs/data-architecture-review.md 完整数据链路审查报告

Tested: npx tsc --noEmit, python -m ruff check .
This commit is contained in:
2569718930@qq.com
2026-05-10 16:48:28 +08:00
parent 8cc7e9a996
commit c0bb2acf78
5 changed files with 233 additions and 16 deletions
+4 -5
View File
@@ -2054,6 +2054,7 @@ def _analyze(
else:
peak_status = "before"
lgbm_val = None
if current_forecasts and deb_val is not None:
lgbm_val, _ = predict_lgbm_daily_high(
city_name=city,
@@ -2069,11 +2070,8 @@ def _analyze(
peak_status=peak_status,
)
if lgbm_val is not None:
current_forecasts["LGBM"] = lgbm_val
blended, winfo = calculate_dynamic_weights(city, current_forecasts)
if blended is not None:
deb_val = blended
deb_weights = winfo
# LGBM is kept as an independent reference, not fed back into DEB
# to avoid circular dependency (DEB → LGBM training → DEB)
deviation_monitor = _build_deviation_monitor(
current_temp=cur_temp,
@@ -2496,6 +2494,7 @@ def _analyze(
"multi_model": {k: v for k, v in current_forecasts.items() if v is not None},
"multi_model_daily": multi_model_daily,
"deb": {"prediction": deb_val, "weights_info": deb_weights},
"lgbm": {"prediction": lgbm_val},
"deviation_monitor": deviation_monitor,
"ensemble": ens_data,
"probabilities": {
+2 -2
View File
@@ -88,8 +88,8 @@ def _env_int(
SCAN_TERMINAL_PAYLOAD_TTL_SEC = max(
5,
int(os.getenv("POLYWEATHER_SCAN_TERMINAL_PAYLOAD_TTL_SEC", "30")),
10,
int(os.getenv("POLYWEATHER_SCAN_TERMINAL_PAYLOAD_TTL_SEC", "120")),
)
SCAN_TERMINAL_BUILD_TIMEOUT_SEC = max(
8,