feat(heartbeat): emit heartbeat event to SQLite

This commit is contained in:
2026-07-10 12:11:18 +08:00
parent 0cf57bfaca
commit 2f4783f1f9
3 changed files with 34 additions and 0 deletions

View File

@@ -13,6 +13,7 @@ router = APIRouter(tags=["monitor"])
class HeartbeatRequest(BaseModel):
account_id: str = Field(..., description="渠道账号唯一标识")
account_name: str | None = Field(None)
tenant_code: str = Field("default", description="业务系统租户编码")
risk_level: int = Field(0, ge=0, le=100)
sent_count_today: int = Field(0, ge=0)

View File

@@ -3,11 +3,14 @@ from __future__ import annotations
import time
from app.clients.pywechat_client import ClientRegistry, OnlineStatus, registry
from app.models.event import EventType, OutboundEvent
from app.repositories.event_store import EventStore
class HeartbeatService:
def __init__(self, registry: ClientRegistry):
self.registry = registry
self.store: EventStore | None = None
def heartbeat(self, account_id: str, payload: dict) -> dict:
client = self.registry.get_or_create(account_id, payload.get("account_name"))
@@ -16,6 +19,20 @@ class HeartbeatService:
client.state.risk_level = payload["risk_level"]
if "sent_count_today" in payload:
client.state.sent_count_today = payload["sent_count_today"]
event = OutboundEvent(
event_type=EventType.HEARTBEAT,
account_id=account_id,
tenant_code=payload.get("tenant_code", "default"),
data={
"login_status": client.state.login_status.value,
"online_status": client.state.online_status.value,
"risk_level": client.state.risk_level,
"sent_count_today": client.state.sent_count_today,
},
)
if self.store is not None:
self.store.save(event)
return {"success": True, "account_id": account_id}
def check_offline_accounts(self, timeout_seconds: int = 120) -> list[dict]:
@@ -30,3 +47,5 @@ class HeartbeatService:
heartbeat_service = HeartbeatService(registry)
from app.repositories.event_store import event_store # noqa: E402
heartbeat_service.store = event_store

View File

@@ -1,6 +1,8 @@
from fastapi.testclient import TestClient
from app.main import app
from app.models.event import EventType
from app.repositories.event_store import event_store
client = TestClient(app)
@@ -64,6 +66,18 @@ def test_heartbeat_and_monitor():
assert any(c["account_id"] == "bot-003" and c["risk_level"] == 10 for c in clients)
def test_heartbeat_creates_event():
event_store.cleanup(0)
client.post("/v1/heartbeat", json={
"account_id": "bot-heartbeat",
"tenant_code": "rescue",
"risk_level": 10,
"sent_count_today": 5,
})
pending = event_store.fetch_pending(limit=10)
assert any(e.event_type == EventType.HEARTBEAT and e.tenant_code == "rescue" for e in pending)
def test_monitor_page():
r = client.get("/monitor")
assert r.status_code == 200