feat: 综合平台services多服务支持+SW网络优先缓存修复+适配层/定时任务完善
This commit is contained in:
+43
-4
@@ -1,17 +1,53 @@
|
||||
"""Agent 上报接收路由(数据写入 metrics.db)"""
|
||||
|
||||
from datetime import datetime
|
||||
import threading
|
||||
import time
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.security import require_agent_key
|
||||
from app.database import get_metrics_session
|
||||
from app.core.timeutils import utcnow
|
||||
from app.database import assets_engine, get_metrics_session
|
||||
from app.models.asset import Asset
|
||||
from app.models.monitor import EventLog, MetricPoint, SecurityCheck, ServerInfo
|
||||
from app.schemas.agent import AgentReport
|
||||
|
||||
router = APIRouter(prefix="/api/agent", tags=["agent"])
|
||||
|
||||
# 内存级频率限制:{asset_id: 上次上报的 monotonic 时间戳}
|
||||
# 同步路由运行在线程池,多线程并发读写需加锁保证“读-判断-写”原子性
|
||||
_last_report_ts: dict = {}
|
||||
_rate_limit_lock = threading.Lock()
|
||||
|
||||
|
||||
def _check_rate_limit(asset_id: int) -> None:
|
||||
"""限制同一资产的上报频率,防止配置错误的 Agent 高频写入填满数据库"""
|
||||
interval = settings.AGENT_REPORT_MIN_INTERVAL
|
||||
if interval <= 0:
|
||||
return
|
||||
now = time.monotonic()
|
||||
with _rate_limit_lock:
|
||||
last = _last_report_ts.get(asset_id)
|
||||
if last is not None and (now - last) < interval:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
|
||||
detail=f"上报过于频繁,同一资产最小间隔 {interval} 秒",
|
||||
)
|
||||
_last_report_ts[asset_id] = now
|
||||
|
||||
|
||||
def _validate_asset_id(asset_id: int) -> None:
|
||||
"""校验上报的 asset_id 在资产库中真实存在,防止脏数据写入"""
|
||||
with Session(assets_engine) as session:
|
||||
asset = session.get(Asset, asset_id)
|
||||
if not asset:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"asset_id={asset_id} 不存在,请先在资产列表中登记该服务器",
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/report",
|
||||
@@ -19,6 +55,9 @@ router = APIRouter(prefix="/api/agent", tags=["agent"])
|
||||
dependencies=[Depends(require_agent_key)],
|
||||
)
|
||||
def report(data: AgentReport, session: Session = Depends(get_metrics_session)) -> dict:
|
||||
_validate_asset_id(data.asset_id)
|
||||
_check_rate_limit(data.asset_id)
|
||||
|
||||
# 资源监控时序
|
||||
if data.metrics:
|
||||
session.add(MetricPoint(asset_id=data.asset_id, **data.metrics.model_dump()))
|
||||
@@ -26,7 +65,7 @@ def report(data: AgentReport, session: Session = Depends(get_metrics_session)) -
|
||||
# 服务器信息快照(每资产一条,覆盖更新)
|
||||
if data.server_info:
|
||||
info = data.server_info.model_dump()
|
||||
info["last_seen"] = datetime.utcnow()
|
||||
info["last_seen"] = utcnow()
|
||||
existing = session.exec(
|
||||
select(ServerInfo).where(ServerInfo.asset_id == data.asset_id)
|
||||
).first()
|
||||
|
||||
Reference in New Issue
Block a user