"""Состояние фоновой инициализации WESP (миграции, sklad, отложенные сервисы).""" from __future__ import annotations import threading import time from typing import Any, Dict, Optional _lock = threading.Lock() _phase = "pending" _message = "Ожидание запуска…" _error: Optional[str] = None _ready = False _started_at: Optional[float] = None _ready_at: Optional[float] = None def _now() -> float: return time.monotonic() def reset_startup_state() -> None: global _phase, _message, _error, _ready, _started_at, _ready_at with _lock: _phase = "pending" _message = "Ожидание запуска…" _error = None _ready = False _started_at = None _ready_at = None def set_startup_phase(phase: str, message: str = "") -> None: global _phase, _message, _started_at with _lock: _phase = phase if message: _message = message if _started_at is None: _started_at = _now() def mark_startup_ready(message: str = "Готово") -> None: global _phase, _message, _ready, _ready_at with _lock: _phase = "ready" _message = message _ready = True _ready_at = _now() def mark_startup_failed(exc: BaseException) -> None: global _phase, _message, _error, _ready with _lock: _phase = "error" _message = "Ошибка инициализации" _error = str(exc) or exc.__class__.__name__ _ready = False def is_startup_ready() -> bool: with _lock: return _ready def startup_status_payload() -> Dict[str, Any]: with _lock: elapsed = None if _started_at is not None: end = _ready_at if _ready and _ready_at is not None else _now() elapsed = round(end - _started_at, 2) return { "ready": _ready, "phase": _phase, "message": _message, "error": _error, "elapsed_sec": elapsed, }