/
liquid-g
/
liquid-code
Обзор
Документация
Войти
/
liquid-g
/
liquid-code
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop-0.4
src/liquidcode/commands/serve/reloader.py
161 строка
6 KB
User
0.4.9 - переработка документации, рефакторинг кода, покрытие тестами 70%
06 июл 2026, 13:37
06 июл 2026, 13:37
79b2ebc
Код
Авторство
О чём код?
import os import signal import subprocess import sys import threading import time from typing import List, Optional, Callable try: from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler except ImportError: Observer = None FileSystemEventHandler = object from .utils import should_ignore class ReloadManager: """ Управляет горячей перезагрузкой сервера. Использует watchdog для отслеживания изменений файлов. """ def __init__( self, app_file: str, host: str, port: int, watch_paths: Optional[List[str]] = None, default_paths: Optional[List[str]] = None, ): self.app_file = app_file self.host = host self.port = port self.watch_paths = watch_paths or [] self.default_paths = default_paths or [".", "src", "config", "templates", "public", ".env"] self.process: Optional[subprocess.Popen] = None self.observer: Optional[Observer] = None self._running = False def start(self) -> None: """Запускает сервер с перезагрузкой.""" if Observer is None: print("⚠️ Для горячей перезагрузки требуется установить watchdog: pip install watchdog") print(" Запуск без перезагрузки...") from .runner import run_server run_server(self.app_file, self.host, self.port) return # Определяем пути для отслеживания watch_paths = self.watch_paths if self.watch_paths else self.default_paths watch_paths = [p for p in watch_paths if os.path.exists(p)] # Настраиваем обработку сигналов signal.signal(signal.SIGINT, self._signal_handler) signal.signal(signal.SIGTERM, self._signal_handler) # Запускаем сервер в первый раз self._start_server() # Настраиваем watchdog event_handler = _ReloadHandler(self._restart_server) self.observer = Observer() for path in watch_paths: if os.path.exists(path): self.observer.schedule(event_handler, path, recursive=True) self.observer.start() self._running = True print(f"👀 Отслеживание изменений включено. Сервер запущен на http://{self.host}:{self.port}") try: while self._running: self.observer.join(timeout=1) if self.process and self.process.poll() is not None: print("⚠️ Сервер неожиданно завершился. Перезапуск...") self._start_server() except KeyboardInterrupt: self.stop() def stop(self) -> None: """Останавливает сервер и наблюдатель.""" self._running = False if self.observer: self.observer.stop() self.observer.join() if self.process: self.process.terminate() self.process.wait() print("\n⏹️ Сервер остановлен") def _start_server(self) -> None: """Запускает дочерний процесс сервера.""" if self.process: self.process.terminate() self.process.wait() cmd = [ sys.executable, "-m", "liquidcode.console", "serve", "--host", self.host, "--port", str(self.port), "--app", self.app_file, ] self.process = subprocess.Popen( cmd, env=os.environ.copy(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1, ) # Поток для вывода логов def log_output(): for line in self.process.stdout: print(line, end="") if self.process.returncode != 0 and self.process.stderr: error = self.process.stderr.read() if error: print(f"⚠️ Ошибка сервера (exit code {self.process.returncode}):", file=sys.stderr) print(error, file=sys.stderr) thread = threading.Thread(target=log_output, daemon=True) thread.start() def _restart_server(self) -> None: """Перезапускает сервер при обнаружении изменений.""" print("\n🔄 Обнаружены изменения, перезапуск сервера...") self._start_server() def _signal_handler(self, sig, frame) -> None: """Обработчик сигналов для корректного завершения.""" self.stop() sys.exit(0) class _ReloadHandler(FileSystemEventHandler): """Обработчик событий файловой системы для watchdog.""" def __init__(self, callback: Callable): self.callback = callback self._last_trigger = time.time() def on_modified(self, event): if event.is_directory: return if should_ignore(event.src_path): return # Ограничиваем частоту перезагрузки now = time.time() if now - self._last_trigger < 1.0: return self._last_trigger = now self.callback()