ADK-gateway/backend/app/scheduler_loop.py
2026-08-04 17:20:08 +08:00

70 lines
2.4 KiB
Python

"""后台任务循环启动器:心跳扫描 / 任务调度 / 任务超时,带分布式锁防多实例重复执行。"""
import asyncio
import logging
import redis.asyncio as aioredis
from app.config import settings
from app.constants import LOCK_HEARTBEAT, LOCK_SCHEDULER, LOCK_TIMEOUT
from app.services.heartbeat import HeartbeatService
from app.services.lock import Lock
from app.services.relay import RelayService
from app.services.scheduler import Scheduler
from app.services.timeout import TimeoutService
logger = logging.getLogger(__name__)
class SchedulerLoop:
def __init__(self, redis: aioredis.Redis):
self.redis = redis
self._tasks: list[asyncio.Task] = []
async def start(self) -> None:
self._tasks.append(asyncio.create_task(self._heartbeat_loop()))
self._tasks.append(asyncio.create_task(self._dispatch_loop()))
self._tasks.append(asyncio.create_task(self._timeout_loop()))
logger.info("scheduler loops started")
async def stop(self) -> None:
for t in self._tasks:
t.cancel()
for t in self._tasks:
try:
await t
except asyncio.CancelledError:
pass
self._tasks.clear()
async def _heartbeat_loop(self) -> None:
hb = HeartbeatService(self.redis)
while True:
await asyncio.sleep(settings.heartbeat_scan_interval)
lock = Lock(self.redis, LOCK_HEARTBEAT)
if await lock.acquire():
try:
await hb.scan()
finally:
await lock.release()
async def _dispatch_loop(self) -> None:
sched = Scheduler(self.redis, relay=RelayService(self.redis))
while True:
await asyncio.sleep(settings.dispatch_interval)
lock = Lock(self.redis, LOCK_SCHEDULER)
if await lock.acquire():
try:
await sched.dispatch_pending(settings.dispatch_batch_size)
finally:
await lock.release()
async def _timeout_loop(self) -> None:
to = TimeoutService(self.redis)
while True:
await asyncio.sleep(settings.task_timeout_check_interval)
lock = Lock(self.redis, LOCK_TIMEOUT)
if await lock.acquire():
try:
await to.check()
finally:
await lock.release()