From 97045a0f72403ed2ecaf3a271b48526e2ea9ad1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AE=D1=80=D0=B8=D0=B9=20=D0=A7=D0=B5=D1=80=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=BA=D0=BE?= Date: Mon, 27 Oct 2025 20:48:31 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=82=D1=83=D1=80=D0=BD=D0=B8=D1=80=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- get_data_new.py | 65 +++++++++++++++++++++++-------------------------- visual.py | 2 +- 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/get_data_new.py b/get_data_new.py index 680c703..c5342df 100644 --- a/get_data_new.py +++ b/get_data_new.py @@ -688,15 +688,6 @@ def run_live_loop( render_thread.start() logger.info("[LIVE_THREAD] render thread spawned") - # поток standings - standings_thread = threading.Thread( - target=Standing_func, - args=(session, league, season, lang, stop_event), - daemon=False, - ) - standings_thread.start() - logger.info("[LIVE_THREAD] standings thread spawned") - try: poll_game_live( session=session, @@ -714,7 +705,6 @@ def run_live_loop( logger.info(f"[LIVE_THREAD] stopping worker threads for game_id={game_id}") render_thread.join() - standings_thread.join() logger.info(f"[LIVE_THREAD] stop live loop for game_id={game_id}") @@ -823,7 +813,6 @@ def render_once_after_game( Referee(state) # === 4. live_status и общий state === - atomic_write_json([state["result"]["live_status"]], "live_status") atomic_write_json(state["result"], out_name) logger.info("[RENDER_ONCE] финальные json сохранены успешно") @@ -1460,6 +1449,8 @@ def Standing_func( # когда мы последний раз успешно обновили standings last_call_ts = 0 + json_seasons = fetch_api_data(session, "seasons", host=HOST, league=league, lang=lang) + season = json_seasons[0]["season"] # как часто вообще можно дёргать standings interval = get_interval_by_name("standings") @@ -1705,64 +1696,70 @@ def get_data_API( logger.info("Для этой команды игр сегодня нет и нет завершённой последней игры.") -def main() -> None: - """ - Главный цикл демона. - - Работает бесконечно: - - собирает данные на сегодня (get_data_API) - - если нужно, следит за матчем в реальном времени до свистка - - после этого уходит спать до 00:05 следующего дня по APP_TZ - - повторяет - - Ctrl+C: - - моментально поднимает stop_event и завершает работу. - """ +def main(): parser = argparse.ArgumentParser() parser.add_argument("--league", default="vtb") parser.add_argument("--team", required=True) parser.add_argument("--lang", default="en") args = parser.parse_args() - while True: - # на каждый "прогон дня" — своя HTTP-сессия и свой stop_event - session = create_session() - stop_event = threading.Event() + # Один общий stop_event на всё приложение. + stop_event = threading.Event() + # Одна сессия для standings-потока. + # Её достаточно, потому что standings не требует суперчастого обновления. + standings_session = create_session() + + # Запускаем standings-поток навсегда (пока процесс жив). + standings_thread = threading.Thread( + target=Standing_func, + args=(standings_session, args.league, None, args.lang, stop_event), + daemon=False, + ) + standings_thread.start() + logger.info("[MAIN] standings thread started (global)") + + # Основной дневной цикл. + while True: + session = create_session() try: get_data_API(session, args.league, args.team, args.lang, stop_event) except KeyboardInterrupt: - logger.info("KeyboardInterrupt -> остановка по запросу оператора") + logger.info("KeyboardInterrupt -> останавливаем всё") stop_event.set() break except Exception as e: - # мы не падаем навсегда, а логируем, чтобы демон продолжил жить logger.exception(f"main loop crash: {e}") - # === сон до завтрашних 00:05 по APP_TZ === + # спим до завтра 00:05 now = datetime.now(APP_TZ) tomorrow = (now + timedelta(days=1)).replace( hour=0, minute=5, second=0, microsecond=0 ) sleep_seconds = (tomorrow - now).total_seconds() if sleep_seconds < 0: - # защита, если вдруг текущее время уже после 00:05 и replace() дал прошедшее tomorrow = (now + timedelta(days=2)).replace( hour=0, minute=5, second=0, microsecond=0 ) sleep_seconds = (tomorrow - now).total_seconds() logger.info( - f"Работа завершена. Засыпаем до {tomorrow.strftime('%d.%m %H:%M')} " + f"Работа за день завершена. Засыпаем до {tomorrow.strftime('%d.%m %H:%M')} " f"(~{round(sleep_seconds/3600, 2)} ч)." ) try: time.sleep(sleep_seconds) except KeyboardInterrupt: - logger.info("KeyboardInterrupt во время сна -> выходим.") + logger.info("KeyboardInterrupt во время сна -> выходим") + stop_event.set() break + # Выход из while True → стопаем standings-поток + stop_event.set() + standings_thread.join() + logger.info("[MAIN] standings thread stopped, shutdown complete") + # идём на новую итерацию while True # (новая сессия / новый stop_event создаются в начале цикла) diff --git a/visual.py b/visual.py index f3f5f48..72ce379 100644 --- a/visual.py +++ b/visual.py @@ -439,13 +439,13 @@ cached_referee = st.session_state.get("referee") league_tag = None if isinstance(cached_game_online, dict): league_tag = (cached_game_online.get("league") or {}).get("tag") - print(cached_game_online.get("comp").get("name")) comp_name = (cached_game_online.get("comp") or {}).get("name").replace(" ", "_") if league_tag: load_data_from_json(f"standings_{league_tag}_{comp_name}") cached_standings = ( st.session_state.get(f"standings_{league_tag}_{comp_name}") if league_tag else None ) + load_data_from_json("scores_quarter") cached_scores_quarter = st.session_state.get("scores_quarter")