Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
"""One process-wide timer thread for periodic maintenance callbacks.
|
||||
|
||||
Replaces the per-child ``while not stop.wait(interval): body()`` daemon
|
||||
threads (delegate heartbeat, durable turn-lease refresher, turn-liveness
|
||||
watchdog). With ~130 in-process subagents those added 2-3 sleeping OS
|
||||
threads per child; this module runs every periodic body on ONE daemon
|
||||
thread ordered by a heap of due times.
|
||||
|
||||
Semantics match the loop they replace: the first call happens ``interval``
|
||||
seconds after :func:`schedule`, and each following call ``interval`` seconds
|
||||
after the previous body *returned* (drift-free wrt. body duration was never
|
||||
a property of the old loops either). A body that returns ``False`` stops
|
||||
itself; a body that raises is logged at debug and rescheduled — one bad
|
||||
callback must never kill the shared thread.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import heapq
|
||||
import itertools
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
from typing import Callable, Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_THREAD_NAME = "hermes-periodic-scheduler"
|
||||
|
||||
|
||||
class ScheduledHandle:
|
||||
"""Cancel token for one scheduled periodic callback."""
|
||||
|
||||
__slots__ = ("_fn", "_interval", "_cancelled", "_scheduler")
|
||||
|
||||
def __init__(self, scheduler: "PeriodicScheduler", fn: Callable[[], object], interval: float):
|
||||
self._scheduler = scheduler
|
||||
self._fn = fn
|
||||
self._interval = interval
|
||||
self._cancelled = False
|
||||
|
||||
@property
|
||||
def cancelled(self) -> bool:
|
||||
return self._cancelled
|
||||
|
||||
def cancel(self, wait: Optional[float] = None) -> None:
|
||||
"""Stop future runs. ``wait`` (seconds) additionally blocks until an
|
||||
in-flight run of this callback finishes — the analogue of
|
||||
``thread.join(timeout=wait)`` on the old per-child thread."""
|
||||
self._scheduler._cancel(self, wait)
|
||||
|
||||
|
||||
class PeriodicScheduler:
|
||||
def __init__(self) -> None:
|
||||
self._cond = threading.Condition()
|
||||
self._heap: list = [] # (due, seq, handle)
|
||||
self._seq = itertools.count()
|
||||
self._thread: Optional[threading.Thread] = None
|
||||
self._running: Optional[ScheduledHandle] = None
|
||||
|
||||
def schedule(self, fn: Callable[[], object], interval: float) -> ScheduledHandle:
|
||||
handle = ScheduledHandle(self, fn, float(interval))
|
||||
with self._cond:
|
||||
heapq.heappush(self._heap, (time.monotonic() + handle._interval, next(self._seq), handle))
|
||||
if self._thread is None or not self._thread.is_alive():
|
||||
self._thread = threading.Thread(target=self._run, name=_THREAD_NAME, daemon=True)
|
||||
self._thread.start()
|
||||
self._cond.notify()
|
||||
return handle
|
||||
|
||||
def _cancel(self, handle: ScheduledHandle, wait: Optional[float]) -> None:
|
||||
with self._cond:
|
||||
handle._cancelled = True
|
||||
self._cond.notify()
|
||||
if wait and self._running is handle and threading.current_thread() is not self._thread:
|
||||
self._cond.wait_for(lambda: self._running is not handle, timeout=wait)
|
||||
|
||||
def _run(self) -> None:
|
||||
while True:
|
||||
with self._cond:
|
||||
while True:
|
||||
if not self._heap:
|
||||
self._cond.wait()
|
||||
continue
|
||||
due, _, handle = self._heap[0]
|
||||
if handle._cancelled:
|
||||
heapq.heappop(self._heap)
|
||||
continue
|
||||
delay = due - time.monotonic()
|
||||
if delay > 0:
|
||||
self._cond.wait(delay)
|
||||
continue
|
||||
heapq.heappop(self._heap)
|
||||
self._running = handle
|
||||
break
|
||||
stop = False
|
||||
try:
|
||||
stop = handle._fn() is False
|
||||
except Exception:
|
||||
logger.debug("periodic callback %r raised", handle._fn, exc_info=True)
|
||||
with self._cond:
|
||||
self._running = None
|
||||
if stop:
|
||||
handle._cancelled = True
|
||||
elif not handle._cancelled:
|
||||
heapq.heappush(
|
||||
self._heap,
|
||||
(time.monotonic() + handle._interval, next(self._seq), handle),
|
||||
)
|
||||
self._cond.notify_all()
|
||||
|
||||
|
||||
_DEFAULT = PeriodicScheduler()
|
||||
|
||||
|
||||
def schedule(fn: Callable[[], object], interval: float) -> ScheduledHandle:
|
||||
"""Run ``fn()`` every ``interval`` seconds on the shared scheduler thread."""
|
||||
return _DEFAULT.schedule(fn, interval)
|
||||
Reference in New Issue
Block a user