process_once(root, fixtures, delay): новые <uuid>_<имя> -> ответ из фикстуры (точное имя, затем префикс, file_uid подставляется) либо INVALID_DOCUMENT, атомарная запись ответа, затем переименование в .done. Цикл python -m src.scan_emulator с корректной остановкой по SIGINT/SIGTERM. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
47 lines
1.8 KiB
Python
47 lines
1.8 KiB
Python
"""Точка входа эмулятора: `python -m src.scan_emulator` (make emulator)."""
|
||
|
||
import signal
|
||
import sys
|
||
import threading
|
||
from types import FrameType
|
||
|
||
from loguru import logger
|
||
|
||
from src.scan_emulator import EmulatorSettings, run
|
||
|
||
|
||
def main(stop: threading.Event | None = None) -> int:
|
||
"""Запуск цикла эмулятора; код возврата процесса. SIGINT/SIGTERM — штатная остановка (0).
|
||
|
||
`stop` — для тестов: событие остановки вместо сигналов. Нет `SCAN_HOTFOLDER_PATH` или корня горячей папки — ошибка
|
||
и ненулевой код (эмулятор не создаёт корень сам: его создаёт и монтирует окружение).
|
||
"""
|
||
try:
|
||
settings = EmulatorSettings.from_env()
|
||
except ValueError as exc:
|
||
logger.error("Эмулятор не запущен: {}", exc)
|
||
return 2
|
||
if not settings.hotfolder_path.is_dir():
|
||
logger.error(
|
||
"Эмулятор не запущен: корень горячей папки {} не существует или не каталог", settings.hotfolder_path
|
||
)
|
||
return 2
|
||
|
||
event = stop if stop is not None else threading.Event()
|
||
|
||
def _on_signal(signum: int, _frame: FrameType | None) -> None:
|
||
logger.info("Получен сигнал {}, останавливаюсь", signal.Signals(signum).name)
|
||
event.set()
|
||
|
||
previous = {sig: signal.signal(sig, _on_signal) for sig in (signal.SIGINT, signal.SIGTERM)}
|
||
try:
|
||
run(settings, event)
|
||
finally:
|
||
for sig, handler in previous.items():
|
||
signal.signal(sig, handler)
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|