diff --git a/services/task-watcher/watcher.py b/services/task-watcher/watcher.py new file mode 100644 index 0000000..15accc1 --- /dev/null +++ b/services/task-watcher/watcher.py @@ -0,0 +1,59 @@ +"""30초마다 current_mode 판정 → queue:paused 토글. + +trading → SET queue:paused 1 EX 600 (10분 TTL — watcher 죽어도 자동 해제) +free → DEL queue:paused +holidays는 1시간마다 refresh (매 loop fetch 부하 회피). +""" +from __future__ import annotations + +import asyncio +import datetime as dt +import logging +import os +from zoneinfo import ZoneInfo + +import redis.asyncio as aioredis + +from mode import current_mode, fetch_holidays, KST + +logger = logging.getLogger(__name__) + +REDIS_URL = os.getenv("REDIS_URL", "redis://192.168.45.54:6379") +PAUSED_KEY = "queue:paused" +LOOP_INTERVAL = 30 # 초 +HOLIDAYS_REFRESH = 3600 # 1시간 +PAUSED_TTL = 600 # 10분 (watcher 죽어도 자동 해제) + + +async def watcher_loop(): + redis = aioredis.from_url(REDIS_URL, decode_responses=False) + holidays = fetch_holidays() + last_holiday_refresh = dt.datetime.now(KST) + last_mode = None + logger.info("task-watcher started (trading window 토글)") + + while True: + try: + now = dt.datetime.now(KST) + # holidays 주기적 refresh + if (now - last_holiday_refresh).total_seconds() >= HOLIDAYS_REFRESH: + holidays = fetch_holidays() + last_holiday_refresh = now + + mode = current_mode(now, holidays) + if mode == "trading": + await redis.set(PAUSED_KEY, b"1", ex=PAUSED_TTL) + else: + await redis.delete(PAUSED_KEY) + + if mode != last_mode: + logger.info("mode 전환: %s → %s (paused=%s)", last_mode, mode, mode == "trading") + last_mode = mode + + await asyncio.sleep(LOOP_INTERVAL) + except asyncio.CancelledError: + logger.info("watcher_loop cancelled") + raise + except Exception: + logger.exception("watcher_loop iteration 실패, 30초 후 재시도") + await asyncio.sleep(LOOP_INTERVAL)