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