feat: persist probe quality and notification outbox
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
import enum
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from sqlalchemy import Column, Integer, String, Float, Boolean, DateTime, Enum, Text
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Boolean, Column, DateTime, Enum, Float, Integer, String
|
||||
from sqlalchemy.orm import DeclarativeBase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.config import Settings
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
pass
|
||||
@@ -16,6 +22,56 @@ class DeviceTypeEnum(str, enum.Enum):
|
||||
other = "other" # 其他
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DeviceMonitoringPolicy:
|
||||
"""Resolved monitoring thresholds for one device.
|
||||
|
||||
Nullable device fields intentionally inherit the runtime defaults so a
|
||||
configuration change can apply to devices that do not need exceptions.
|
||||
"""
|
||||
|
||||
probe_packets_per_round: int
|
||||
offline_consecutive_rounds: int
|
||||
degraded_window_rounds: int
|
||||
degraded_loss_percent: float
|
||||
recovery_consecutive_clean_rounds: int
|
||||
|
||||
@classmethod
|
||||
def from_device(
|
||||
cls,
|
||||
device: "Device",
|
||||
settings: "Settings",
|
||||
) -> "DeviceMonitoringPolicy":
|
||||
"""Resolve device overrides without changing the stored device."""
|
||||
return cls(
|
||||
probe_packets_per_round=(
|
||||
device.probe_packets_per_round
|
||||
if device.probe_packets_per_round is not None
|
||||
else settings.probe_packets_per_round
|
||||
),
|
||||
offline_consecutive_rounds=(
|
||||
device.offline_consecutive_rounds
|
||||
if device.offline_consecutive_rounds is not None
|
||||
else settings.offline_consecutive_rounds
|
||||
),
|
||||
degraded_window_rounds=(
|
||||
device.degraded_window_rounds
|
||||
if device.degraded_window_rounds is not None
|
||||
else settings.degraded_window_rounds
|
||||
),
|
||||
degraded_loss_percent=(
|
||||
device.degraded_loss_percent
|
||||
if device.degraded_loss_percent is not None
|
||||
else settings.degraded_loss_percent
|
||||
),
|
||||
recovery_consecutive_clean_rounds=(
|
||||
device.recovery_consecutive_clean_rounds
|
||||
if device.recovery_consecutive_clean_rounds is not None
|
||||
else settings.recovery_consecutive_clean_rounds
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class Device(Base):
|
||||
__tablename__ = "devices"
|
||||
|
||||
@@ -32,8 +88,39 @@ class Device(Base):
|
||||
alert_threshold = Column(Integer, default=5, comment="连续失败次数判离线")
|
||||
is_enabled = Column(Boolean, default=True, comment="是否启用监控")
|
||||
|
||||
# 设备级监测策略覆盖;NULL 时使用运行环境中的全局默认值。
|
||||
probe_packets_per_round = Column(
|
||||
Integer,
|
||||
nullable=True,
|
||||
comment="单轮探测发包数覆盖",
|
||||
)
|
||||
offline_consecutive_rounds = Column(
|
||||
Integer,
|
||||
nullable=True,
|
||||
comment="连续全丢包离线轮数覆盖",
|
||||
)
|
||||
degraded_window_rounds = Column(
|
||||
Integer,
|
||||
nullable=True,
|
||||
comment="故障丢包滑动窗口轮数覆盖",
|
||||
)
|
||||
degraded_loss_percent = Column(
|
||||
Float,
|
||||
nullable=True,
|
||||
comment="故障丢包率阈值覆盖",
|
||||
)
|
||||
recovery_consecutive_clean_rounds = Column(
|
||||
Integer,
|
||||
nullable=True,
|
||||
comment="连续零丢包恢复轮数覆盖",
|
||||
)
|
||||
|
||||
# 运行状态
|
||||
current_status = Column(String(16), default="unknown", comment="当前状态: online/offline/unknown")
|
||||
current_status = Column(
|
||||
String(16),
|
||||
default="unknown",
|
||||
comment="当前状态: online/degraded/offline/unknown",
|
||||
)
|
||||
consecutive_failures = Column(Integer, default=0, comment="当前连续失败次数")
|
||||
last_ping_time = Column(DateTime, nullable=True, comment="最后一次 ping 时间")
|
||||
last_online_time = Column(DateTime, nullable=True, comment="最后一次在线时间")
|
||||
|
||||
Reference in New Issue
Block a user