From ad9d66d690e7fad6fc7e517dcf8a69636a190ae0 Mon Sep 17 00:00:00 2001 From: Vlasov Dmitriy Date: Tue, 16 Jun 2026 14:02:59 +0300 Subject: [PATCH] timer: init error hotfix --- microagent/timer.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/microagent/timer.py b/microagent/timer.py index c771b46..910612d 100644 --- a/microagent/timer.py +++ b/microagent/timer.py @@ -24,7 +24,7 @@ async def cron_handler(self): import re import time from collections.abc import Callable -from dataclasses import dataclass +from dataclasses import dataclass, field from datetime import datetime, timedelta, timezone from typing import TYPE_CHECKING, ClassVar, NamedTuple, TypedDict @@ -54,12 +54,16 @@ def __str__(self) -> str: return f'[{self.spec}]' +class PeriodicState(TypedDict, total=False): + timer_handle: asyncio.TimerHandle + running_task: asyncio.Task + + class PeriodicMixin: agent: 'MicroAgent' handler: Callable timeout: float - _timer_handle: asyncio.TimerHandle | None = None - _running_task: asyncio.Task | None = None + _state: PeriodicState async def call(self) -> None: try: @@ -75,13 +79,14 @@ async def call(self) -> None: self.agent.log.exception(f'Periodic Exception: {exc}') def start(self, start_after: float) -> None: - self._timer_handle = asyncio.get_running_loop().call_later(start_after, _periodic, self) # type: ignore[arg-type] + self._state['timer_handle'] = asyncio.get_running_loop().call_later( + start_after, _periodic, self) # type: ignore[arg-type] def cancel(self) -> None: - if self._timer_handle is not None: - self._timer_handle.cancel() - if self._running_task is not None and not self._running_task.done(): - self._running_task.cancel() + if (timer_handle := self._state.get('timer_handle')) is not None: + timer_handle.cancel() + if (running_task := self._state.get('running_task')) is not None and not running_task.done(): + running_task.cancel() class PeriodicArgs(TypedDict): @@ -97,6 +102,7 @@ class PeriodicTask(PeriodicMixin): period: float timeout: float start_after: float + _state: PeriodicState = field(default_factory=PeriodicState) _register: ClassVar[dict[BoundKey, PeriodicArgs]] = {} @@ -115,6 +121,7 @@ class CRONTask(PeriodicMixin): handler: PeriodicFunc cron: CRON timeout: float + _state: PeriodicState = field(default_factory=PeriodicState) _register: ClassVar[dict[BoundKey, CRONArgs]] = {} @@ -135,9 +142,9 @@ def period(self) -> float: def _periodic(task: PeriodicTask | CRONTask) -> asyncio.Task: - task._timer_handle = asyncio.get_running_loop().call_later(task.period, _periodic, task) + task._state['timer_handle'] = asyncio.get_running_loop().call_later(task.period, _periodic, task) running = asyncio.create_task(task.call()) - task._running_task = running + task._state['running_task'] = running return running