feat(heartbeat): emit heartbeat event to SQLite
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user