diff --git a/agents/stock/workspace/scripts/realtime_hub.py b/agents/stock/workspace/scripts/realtime_hub.py index 8aacbf7..c489536 100644 --- a/agents/stock/workspace/scripts/realtime_hub.py +++ b/agents/stock/workspace/scripts/realtime_hub.py @@ -45,6 +45,8 @@ _BACKOFF_MAX = 30.0 _MAX_CONN_AGE = 25 * 60 # recv 타임아웃 — 이 시간 내 아무것도 안 오면 루프 돌며 stop/age 체크 _RECV_TIMEOUT = 5.0 +# 장 마감 시간대 재확인 주기 — 연결 안 하고 대기하며 이 간격으로 개장 여부 폴링 +_CLOSED_POLL_SEC = 60.0 def _ws_url() -> str: @@ -135,19 +137,33 @@ class RealtimeHub: pass # ---- 내부: 연결 루프 ---- + def _market_open(self) -> bool: + """장 시간대(정규장·NXT) 여부. behive_web._market_phase_state 재사용(지연 import로 순환 회피). + 판정 실패 시 보수적으로 True(연결 유지) — 게이팅 때문에 시세가 끊기는 일은 없게.""" + try: + import behive_web + return bool(behive_web._market_phase_state().get('active')) + except Exception: + return True + def _run(self) -> None: backoff = _BACKOFF_START while not self._stop.is_set(): + if not self._market_open(): + # 장 외(주말·휴장·장외 시간) → 연결 안 하고 대기. 재연결 폭주·로그 노이즈 방지. + self._connected.clear() + self._stop.wait(_CLOSED_POLL_SEC) + continue try: self._connect_once() - backoff = _BACKOFF_START # 정상 종료(선제 재연결 등) → 백오프 리셋 + backoff = _BACKOFF_START # 정상 종료(선제 재연결·장 마감 등) → 백오프 리셋 except Exception as e: self.last_error = f'{type(e).__name__}: {e}' self._connected.clear() sys.stderr.write(f'[realtime-hub] 연결 끊김/실패: {self.last_error}\n') if self._stop.is_set(): break - time.sleep(backoff) + self._stop.wait(backoff) backoff = min(backoff * 2, _BACKOFF_MAX) def _connect_once(self) -> None: @@ -175,10 +191,17 @@ class RealtimeHub: self._send_reg(codes) # 3) 수신 루프 + _last_mkt_check = time.time() while not self._stop.is_set(): if time.time() - self.connected_at > _MAX_CONN_AGE: sys.stderr.write('[realtime-hub] 토큰 만료 전 선제 재연결\n') return # 정상 종료 → _run이 즉시 재연결 + # 장 마감되면 연결 종료 → _run이 대기 모드로 전환. 30초마다만 확인(매 recv마다 X). + if time.time() - _last_mkt_check > 30: + _last_mkt_check = time.time() + if not self._market_open(): + sys.stderr.write('[realtime-hub] 장 마감 → 연결 종료, 대기 모드\n') + return try: raw = ws.recv() except websocket.WebSocketTimeoutException: