diff --git a/Dabit Time Manager.spec b/Dabit Time Manager.spec index 3bd3ebb..0d96777 100644 --- a/Dabit Time Manager.spec +++ b/Dabit Time Manager.spec @@ -22,7 +22,7 @@ exe = EXE( a.binaries, a.datas, [], - name='DabitTimeManager_v1.0', + name='DabitTimeManager_v1.1', debug=False, bootloader_ignore_signals=False, strip=False, diff --git a/services/drift_monitor.py b/services/drift_monitor.py index e75c37b..780e615 100644 --- a/services/drift_monitor.py +++ b/services/drift_monitor.py @@ -16,7 +16,8 @@ class DriftMonitor: def __init__(self): self._timer: threading.Timer | None = None - self._hourly_timer: threading.Timer | None = None + self._hourly_thread: threading.Thread | None = None + self._hourly_stop_event: threading.Event | None = None self._running = False self._hourly_running = False self._interval = DEFAULT_MONITOR_INTERVAL @@ -72,36 +73,49 @@ class DriftMonitor: if self._hourly_running: return self._hourly_running = True - self._schedule_hourly() + self._hourly_stop_event = threading.Event() + self._hourly_thread = threading.Thread(target=self._hourly_loop, daemon=True) + self._hourly_thread.start() def stop_hourly(self): """매시 정시 읽기 중지.""" self._hourly_running = False - if self._hourly_timer: - self._hourly_timer.cancel() - self._hourly_timer = None + if self._hourly_stop_event: + self._hourly_stop_event.set() + self._hourly_thread = None - def _schedule_hourly(self): - """다음 정시까지 대기 후 읽기 예약.""" - if not self._hourly_running: - return - now = datetime.now() - # 다음 정시: 현재 시 + 1, 분/초 = 0 - next_hour = now.replace(minute=0, second=0, microsecond=0) - next_hour = next_hour + timedelta(hours=1) - delay = (next_hour - now).total_seconds() - if self._on_error: - self._on_error(f"정시 읽기 예약: {next_hour.strftime('%H:%M:%S')} ({delay:.0f}초 후)") - self._hourly_timer = threading.Timer(delay, self._hourly_tick) - self._hourly_timer.daemon = True - self._hourly_timer.start() + def _hourly_loop(self): + """매시 정시 읽기 루프 (절전 복귀 대응).""" + while self._hourly_running: + now = datetime.now() + next_hour = now.replace(minute=0, second=0, microsecond=0) + timedelta(hours=1) - def _hourly_tick(self): - """정시 도달 시 읽기 실행 후 다음 정시 예약.""" - if not self._hourly_running: - return - self._do_read(schedule_next=False) - self._schedule_hourly() + if self._on_error: + delay = (next_hour - now).total_seconds() + self._on_error(f"정시 읽기 예약: {next_hour.strftime('%H:%M:%S')} ({delay:.0f}초 후)") + + # 30초 간격 폴링으로 정시 대기 (절전 복귀 시 즉시 감지) + while self._hourly_running: + now = datetime.now() + if now >= next_hour: + break + remaining = (next_hour - now).total_seconds() + wait = min(remaining, 30) + if self._hourly_stop_event.wait(timeout=wait): + return # 중지 요청 + + if not self._hourly_running: + break + + # 정시 읽기 실행 + try: + self._do_read(schedule_next=False) + except Exception as e: + if self._on_error: + try: + self._on_error(f"정시 읽기 오류: {e}") + except: + pass def read_once(self): """즉시 한 번 읽기 (별도 스레드)."""