diff --git a/get_data.py b/get_data.py index 70b9021..cb99a7a 100644 --- a/get_data.py +++ b/get_data.py @@ -91,6 +91,8 @@ SEASON = None GAME_START_DT = None # datetime начала матча (локальная из календаря) GAME_TODAY = False # флаг: игра сегодня GAME_SOON = False # флаг: игра сегодня и скоро (<1 часа) +OFFLINE_SWITCH_AT = None # timestamp, когда надо уйти в оффлайн +OFFLINE_DELAY_SEC = 600 # 10 минут # общая очередь results_q = queue.Queue() @@ -129,10 +131,11 @@ def start_offline_threads(season, game_id): global threads_offline, CURRENT_THREADS_MODE, stop_event_offline, latest_data if CURRENT_THREADS_MODE == "offline": + logger.debug("[threads] already in OFFLINE mode → skip start_offline_threads") return stop_live_threads() - + logger.info("[threads] switching to OFFLINE mode ...") # 🔹 очищаем latest_data безопасно, чтобы не ломать структуру keep_keys = { "game", @@ -267,12 +270,24 @@ def stop_live_threads(): """Гасим только live-треды.""" global threads_live if not threads_live: + logger.info("[threads] LIVE threads stopped (nothing to stop)") return + + logger.info(f"[threads] Stopping {len(threads_live)} LIVE thread(s)...") stop_event_live.set() + + still_alive = [] for t in threads_live: - t.join(timeout=1) + t.join(timeout=2) + if t.is_alive(): + logger.warning(f"[threads] LIVE thread is still alive: {t.name}") + still_alive.append(t.name) + threads_live = [] - logger.info("[threads] LIVE threads stopped") + if still_alive: + logger.warning(f"[threads] Some LIVE threads did not stop: {still_alive}") + else: + logger.info("[threads] LIVE threads stopped") def stop_offline_threads(): @@ -333,6 +348,16 @@ def get_data_from_API( # Получение результатов из всех запущенных потоков def results_consumer(): while not stop_event.is_set(): + # ⬇️ проверяем, не пора ли в оффлайн (отложенный переход) + off_at = globals().get("OFFLINE_SWITCH_AT") + if off_at is not None and time.time() >= off_at: + # делаем переход ТОЛЬКО если ещё не оффлайн + if globals().get("CURRENT_THREADS_MODE") != "offline": + logger.info("[status] switching to OFFLINE (delayed)") + stop_live_threads() + start_offline_threads(SEASON, GAME_ID) + # чтобы не повторять + globals()["OFFLINE_SWITCH_AT"] = None try: msg = results_q.get(timeout=0.5) except queue.Empty: @@ -435,32 +460,43 @@ def results_consumer(): raw_ls_status_low = str(raw_ls_status).lower() finished_markers = [ - "finished", - "result", - "resultconfirmed", - "ended", - "final", - "game over", + "finished", "result", "resultconfirmed", + "ended", "final", "game over", ] - # матч ЗАКОНЧЕН → гасим live и включаем offline + # 1) матч ЗАКОНЧЕН → запускаем ОТСРОЧЕННЫЙ переход if any(m in raw_ls_status_low for m in finished_markers): - logger.info("[status] match finished → switch to OFFLINE") - if ( - GAME_START_DT - and GAME_START_DT.date() == datetime.now().date() - ): - globals()["STATUS"] = "finished_today" + now_ts = time.time() + # если ещё не назначали переход — назначим + if globals().get("OFFLINE_SWITCH_AT") is None: + switch_at = now_ts + globals().get("OFFLINE_DELAY_SEC", 600) + globals()["OFFLINE_SWITCH_AT"] = switch_at + + # статус тоже обозначим, что он завершён, но ждёт + if ( + GAME_START_DT + and GAME_START_DT.date() == datetime.now().date() + ): + globals()["STATUS"] = "finished_wait" + else: + globals()["STATUS"] = "finished_wait" + + human_time = datetime.fromtimestamp(switch_at).strftime("%H:%M:%S") + logger.info( + f"[status] match finished → will switch to OFFLINE at {human_time} " + f"(in {globals().get('OFFLINE_DELAY_SEC', 600)}s)" + ) else: - globals()["STATUS"] = "finished" + # уже ждём — можно в debug + logger.debug("[status] match finished → OFFLINE already scheduled") - stop_live_threads() - start_offline_threads(SEASON, GAME_ID) + # 2) матч снова стал онлайном → СБРАСЫВАЕМ отложенный переход + elif "online" in raw_ls_status_low or "live" in raw_ls_status_low: + # если до этого стояла отложка — уберём + if globals().get("OFFLINE_SWITCH_AT") is not None: + logger.info("[status] match back to LIVE → cancel scheduled OFFLINE") + globals()["OFFLINE_SWITCH_AT"] = None - # матч СТАЛ онлайном (напр., из Scheduled → Online) - elif ( - "online" in raw_ls_status_low or "live" in raw_ls_status_low - ): if globals().get("STATUS") not in ["live", "live_soon"]: logger.info( "[status] match became LIVE → switch to LIVE threads" @@ -469,9 +505,8 @@ def results_consumer(): start_live_threads(SEASON, GAME_ID) except Exception as e: - logger.warning( - f"results_consumer: live-status postprocess error: {e}" - ) + logger.warning(f"results_consumer: live-status postprocess error: {e}") + else: if source == "game": @@ -1050,18 +1085,18 @@ async def status(request: Request): elif status_raw in ["live_soon"]: gs_class = "live" gs_text = "🟢 GAME TODAY (soon)" - elif status_raw == "today_not_started": + elif status_raw in ["finished_wait"]: gs_class = "upcoming" - gs_text = "🟡 Game today, not started" + # покажем, что он ДОЖИДАЕТСЯ оффлайна + off_at = OFFLINE_SWITCH_AT + if off_at: + human = datetime.fromtimestamp(off_at).strftime("%H:%M:%S") + gs_text = f"🟡 Game finished, cooling down → OFFLINE at {human}" + else: + gs_text = "🟡 Game finished, cooling down" elif status_raw in ["finished_today", "finished"]: gs_class = "finished" gs_text = "🔴 Game finished" - elif status_raw == "no_game_today": - gs_class = "unknown" - gs_text = "⚪ No game today" - else: - gs_class = "unknown" - gs_text = "⚪ UNKNOWN" html = f"""