get_json поменял местами данные

This commit is contained in:
2025-10-29 11:44:13 +03:00
parent 6721951c34
commit 7b44ab3d5d

View File

@@ -1,5 +1,5 @@
import time import time
import os import os, tempfile
import json import json
import tempfile import tempfile
import argparse import argparse
@@ -9,6 +9,7 @@ import logging.config
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
from typing import Any, Dict, List, Tuple, Optional from typing import Any, Dict, List, Tuple, Optional
from pathlib import Path
import pandas as pd import pandas as pd
import numpy as np import numpy as np
@@ -23,7 +24,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
# 1. Константы / глобальные объекты # 1. Константы / глобальные объекты
# ============================================================================ # ============================================================================
HOST = "https://ref.russiabasket.org" HOST = "https://deti.russiabasket.org"
# Таймзона, в которой мы считаем время матчей / расписания / сна до завтра # Таймзона, в которой мы считаем время матчей / расписания / сна до завтра
APP_TZ = ZoneInfo("Europe/Moscow") APP_TZ = ZoneInfo("Europe/Moscow")
@@ -35,7 +36,8 @@ TELEGRAM_BOT_TOKEN = "7639240596:AAH0YtdQoWZSC-_R_EW4wKAHHNLIA0F_ARY"
TELEGRAM_CHAT_ID = -4803699526 TELEGRAM_CHAT_ID = -4803699526
# Глобальный лок для потокобезопасной записи JSON # Глобальный лок для потокобезопасной записи JSON
_write_lock = threading.Lock() _write_lock_api = threading.Lock()
_write_lock_out = threading.Lock()
_pregame_done_for_game = {} _pregame_done_for_game = {}
# Карта всех ручек API, с интервалами опроса в секундах. # Карта всех ручек API, с интервалами опроса в секундах.
@@ -146,28 +148,41 @@ logger.handlers[2].formatter.use_emoji = True
# ============================================================================ # ============================================================================
def atomic_write_json(data: Any, name: str, out_dir: str = "static") -> None: def _select_lock(path: str):
filename = os.path.basename(path)
# все сырые файлы мы называем api_*.json (api_game.json, api_box-score.json, ...)
if filename.startswith("api_"):
return _write_lock_api
return _write_lock_out
def atomic_write_json(path: str, data: Any) -> None:
""" """
Потокобезопасная запись JSON в static/<name>.json. Безопасно записывает JSON:
1. Сериализуем в память (без локов).
Запись делается через временный файл + os.replace, чтобы: 2. Под коротким локом - пишем tmp и делаем os.replace().
- читатели не получили битый файл во время перезаписи;
- не было гонок между render_loop и poll_game_live.
""" """
os.makedirs(out_dir, exist_ok=True) # 1. Готовим данные заранее
filename = os.path.join(out_dir, f"{name}.json") # ensure_ascii=False чтобы не терять юникод, indent=None чтобы не раздувать файл
payload = json.dumps(data, ensure_ascii=False, separators=(",", ":"))
with _write_lock: target = Path(path)
with tempfile.NamedTemporaryFile( tmp_fd, tmp_path = tempfile.mkstemp(
"w", delete=False, dir=out_dir, encoding="utf-8" dir=target.parent,
) as tmp_file: prefix=target.name + ".tmp.",
json.dump(data, tmp_file, ensure_ascii=False, indent=2) text=True,
tmp_file.flush() )
os.fsync(tmp_file.fileno()) os.close(tmp_fd) # мы будем писать сами
tmp_name = tmp_file.name
os.replace(tmp_name, filename) lock = _select_lock(path)
with lock:
# 2a. Записываем полностью во временный файл
with open(tmp_path, "w", encoding="utf-8") as f:
f.write(payload)
f.flush()
os.fsync(f.fileno())
# 2b. Атомарно подменяем
os.replace(tmp_path, target)
def read_local_json(name: str, in_dir: str = "static") -> Optional[dict]: def read_local_json(name: str, in_dir: str = "static") -> Optional[dict]:
""" """
@@ -251,7 +266,7 @@ def get_json(session: requests.Session, url: str, name: str) -> Any:
resp = session.get(url, timeout=10) resp = session.get(url, timeout=10)
resp.raise_for_status() resp.raise_for_status()
data = resp.json() data = resp.json()
atomic_write_json(data, f"api_{name}") atomic_write_json(f"api_{name}", data)
return data return data