import asyncio import logging import pydantic log = logging.getLogger(__name__) class WorkerConfig(pydantic.BaseModel): INTERVAL_SECONDS: int = 60 class WorkerBase: def __init__(self, config: WorkerConfig) -> None: self.config = config self._task: asyncio.Task[None] | None = None self._stop_event = asyncio.Event() log.info('Worker initialized (interval=%ds)', config.INTERVAL_SECONDS) async def _cycle_func(self) -> None: raise NotImplementedError async def start(self) -> None: if self._task is not None: log.warning('Worker already running') return self._stop_event.clear() self._task = asyncio.create_task(self._run()) log.info('Worker started') async def stop(self) -> None: if self._task is None: log.warning('Worker not running') return self._stop_event.set() try: await asyncio.wait_for(self._task, timeout=5.0) except TimeoutError: log.warning('Worker did not stop in time, cancelling') self._task.cancel() try: await self._task except asyncio.CancelledError: pass except asyncio.CancelledError: log.info('Worker task cancelled') self._task = None log.info('Worker stopped') async def _run(self) -> None: while not self._stop_event.is_set(): try: await self._cycle_func() except Exception: log.exception('Error in worker cycle') try: await asyncio.wait_for(self._stop_event.wait(), timeout=self.config.INTERVAL_SECONDS) except TimeoutError: pass # Время вышло, продолжаем