diff --git a/backend/app/worker.py b/backend/app/worker.py index 43d4685..a6a09c6 100644 --- a/backend/app/worker.py +++ b/backend/app/worker.py @@ -129,19 +129,20 @@ async def generate_ai_predictions(only_missing: bool = True) -> None: # ── 2.5) 결과 자동 정산 (관리자 입력 불필요) ──────────────── async def settle_matches() -> None: - """킥오프 + result_settle_hours 경과한 미정산 경기를 외부 스코어로 자동 채점. + """킥오프가 지난 미정산 경기를, 소스가 FINISHED 로 보고하는 즉시 채점·종료. - 외부 소스(openfootball/football-data)에서 확정 스코어를 수집해 apply_result - 호출 → 채점·유저 포인트 집계·finished_at 기록. 직후 결과 메일을 발송한다. - 소스에 스코어가 아직 없으면 다음 틱에 재시도. + 킥오프 이후의 미정산 경기를 폴링하되, 외부 소스(football-data)가 FINISHED 로 + 확정 스코어를 줄 때만 apply_result → 채점·유저 포인트 집계·finished_at·메일. + 경기 중(IN_PLAY)에는 FINISHED 가 아니라 결과에 안 잡혀 자동 스킵된다(조기 종료 없음). + 아직 FINISHED 가 아니면 다음 틱(5분)에 재시도 → 종료 후 최대 1틱 내 반영. """ now = now_utc() - cutoff = now - timedelta(hours=settings.result_settle_hours) async with SessionLocal() as db: pending = ( await db.execute(select(Match).where(Match.result_outcome.is_(None))) ).scalars().all() - due = [m.match_id for m in pending if ensure_aware(m.kickoff_at) <= cutoff] + # 킥오프가 지난 경기만 (소스가 FINISHED 줄 수 있는 시점) + due = [m.match_id for m in pending if ensure_aware(m.kickoff_at) <= now] if due: results = await fetch_results() @@ -163,7 +164,7 @@ async def settle_matches() -> None: settled += 1 log.info("settle: %s 자동 정산 %d-%d", mid, sc[0], sc[1]) if settled == 0: - log.info("settle: %d경기 정산 대기 — 외부 스코어 아직 없음", len(due)) + log.info("settle: %d경기 진행/대기 — 아직 FINISHED 아님", len(due)) await maybe_send_result_emails() @@ -284,14 +285,13 @@ async def main() -> None: sched.start() log.info( "scheduling-server started — schedule sync daily %02d:%02d · status every %ss · " - "AI gen daily %02d:%02d %s · auto-settle 킥오프+%dh (every %ss) · 맞춘사람만=%s", + "AI gen daily %02d:%02d %s · auto-settle on FINISHED (poll every %ss) · 맞춘사람만=%s", settings.schedule_sync_hour, settings.schedule_sync_minute, settings.status_tick_seconds, settings.ai_generate_hour, settings.ai_generate_minute, settings.timezone, - settings.result_settle_hours, settings.settle_tick_seconds, settings.result_email_correct_only, )