성과 통계 인메모리 캐시 추가 (GET /api/lotto/stats/performance)

매 요청마다 전체 recommendations 조회하던 구조를 캐시로 개선.
갱신 시점: 새 회차 채점 직후(_sync_and_check) + TTL 1시간 만료 폴백

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 02:00:54 +09:00
parent 732d78becc
commit f1eab292a2

View File

@@ -1,4 +1,5 @@
import os import os
import time
from typing import Optional, List, Dict, Any, Tuple from typing import Optional, List, Dict, Any, Tuple
from fastapi import FastAPI, HTTPException from fastapi import FastAPI, HTTPException
from pydantic import BaseModel from pydantic import BaseModel
@@ -42,6 +43,17 @@ scheduler = BackgroundScheduler(timezone=os.getenv("TZ", "Asia/Seoul"))
ALL_URL = os.getenv("LOTTO_ALL_URL", "https://smok95.github.io/lotto/results/all.json") ALL_URL = os.getenv("LOTTO_ALL_URL", "https://smok95.github.io/lotto/results/all.json")
LATEST_URL = os.getenv("LOTTO_LATEST_URL", "https://smok95.github.io/lotto/results/latest.json") LATEST_URL = os.getenv("LOTTO_LATEST_URL", "https://smok95.github.io/lotto/results/latest.json")
# ── 성과 통계 인메모리 캐시 ───────────────────────────────────────────────────
# 채점 데이터는 하루 2번 스케줄러 실행 시에만 갱신되므로 인메모리 캐시로 충분
_PERF_CACHE: Dict[str, Any] = {"data": None, "at": 0.0}
_PERF_CACHE_TTL = 3600 # 1시간 (스케줄러 미실행 상황 대비 폴백)
def _refresh_perf_cache() -> None:
_PERF_CACHE["data"] = get_recommendation_performance()
_PERF_CACHE["at"] = time.time()
print("[PerfCache] 성과 통계 캐시 갱신")
@app.on_event("startup") @app.on_event("startup")
def on_startup(): def on_startup():
@@ -53,6 +65,7 @@ def on_startup():
res = sync_latest(LATEST_URL) res = sync_latest(LATEST_URL)
if res["was_new"]: if res["was_new"]:
check_results_for_draw(res["drawNo"]) check_results_for_draw(res["drawNo"])
_refresh_perf_cache() # 새 채점 결과 반영 → 즉시 갱신
scheduler.add_job(_sync_and_check, "cron", hour="9,21", minute=10) scheduler.add_job(_sync_and_check, "cron", hour="9,21", minute=10)
@@ -170,15 +183,16 @@ def api_stats():
} }
# ── 추천 성과 통계 (Phase 1) ───────────────────────────────────────────────── # ── 추천 성과 통계 (Phase 1, 인메모리 캐시) ──────────────────────────────────
@app.get("/api/lotto/stats/performance") @app.get("/api/lotto/stats/performance")
def api_performance_stats(): def api_performance_stats():
""" """
채점된 추천 이력 기반 성과 통계. 채점된 추천 이력 기반 성과 통계 (캐시 반환).
- 평균 일치 개수, 분포, 등수별 현황 캐시 갱신 시점: 새 회차 채점 직후 | TTL 1시간 만료 시
- 무작위 대비 개선율 (이론 기댓값 0.8개 기준)
""" """
return get_recommendation_performance() if _PERF_CACHE["data"] is None or time.time() - _PERF_CACHE["at"] > _PERF_CACHE_TTL:
_refresh_perf_cache()
return _PERF_CACHE["data"]
# ── 회차 공략 리포트 (Phase 1) ──────────────────────────────────────────────── # ── 회차 공략 리포트 (Phase 1) ────────────────────────────────────────────────