ForcePilot/backend/package/yuxi/channels/adapters/whatsapp/heartbeat.py
Kris e9b57546ea feat(whatsapp): 新增WhatsApp适配器完整功能模块
新增大量WhatsApp适配器相关代码,包括账号管理、会话处理、消息收发、验证授权、媒体处理、互动命令、审批流程、健康检测等完整功能模块,搭建基础的Baileys协议WhatsApp接入能力
2026-05-12 00:51:58 +08:00

70 lines
2.5 KiB
Python

from __future__ import annotations
import asyncio
from collections.abc import Awaitable, Callable
from yuxi.utils.logging_config import logger
class HeartbeatManager:
MAX_BACKOFF = 300.0
def __init__(self, bridge, interval: float = 30.0):
self._bridge = bridge
self._interval = interval
self._task: asyncio.Task | None = None
self._on_unhealthy: Callable[[str], Awaitable[None]] | None = None
self._consecutive_failures = 0
self._stopping = False
def on_unhealthy(self, handler: Callable[[str], Awaitable[None]]) -> None:
self._on_unhealthy = handler
async def start(self) -> None:
self._stopping = False
if self._task and not self._task.done():
return
self._task = asyncio.create_task(self._loop())
async def stop(self) -> None:
self._stopping = True
if self._task:
self._task.cancel()
try:
await self._task
except asyncio.CancelledError:
pass
self._task = None
def _backoff_seconds(self) -> float:
if self._consecutive_failures == 0:
return self._interval
return min(self._interval * (2 ** (self._consecutive_failures - 1)), self.MAX_BACKOFF)
async def _loop(self) -> None:
while True:
try:
delay = self._backoff_seconds()
await asyncio.sleep(delay)
if self._stopping:
break
health = await self._bridge.health_check()
if health.status == "unhealthy":
self._consecutive_failures += 1
logger.warning(
f"Heartbeat detected unhealthy bridge "
f"(failures: {self._consecutive_failures}, backoff: {self._backoff_seconds():.0f}s): "
f"{health.last_error}"
)
if self._consecutive_failures >= 3 and self._on_unhealthy:
await self._on_unhealthy(health.last_error or "unknown")
else:
self._consecutive_failures = 0
except asyncio.CancelledError:
break
except Exception as e:
self._consecutive_failures += 1
logger.error(f"Heartbeat error (failures: {self._consecutive_failures}): {e}")
if self._consecutive_failures >= 3 and self._on_unhealthy:
await self._on_unhealthy(str(e))