ForcePilot/backend/package/yuxi/channels/contract/dtos/health_check.py
Kris 00092c818e chore: 批量代码优化与规范完善
本次提交包含多项代码优化与规范修正:
1. 文档与注释优化:修正注释术语、补充注解与FR编号
2. 代码格式调整:统一空格、换行与缩进规范
3. 类型与接口完善:补充__all__导出、修正返回类型注解
4. 错误处理增强:新增领域错误类与校验逻辑
5. 依赖与导入调整:修复路径引用、统一时区导入
6. 协议与契约更新:完善接口文档与一致性注解
2026-07-03 19:18:13 +08:00

168 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""健康检查结果 DTO。
定义渠道插件健康检查的不可变值对象,作为 ``DoctorAdapter.checkConnectivity``
方法的返回值PRD §4.0.4 核心方法 6健康检查。与 ``doctor.py`` 中的
深度诊断 DTO 不同,本 DTO 仅描述轻量级健康探针结果。
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from typing import Any, Literal
from yuxi.channels.contract.dtos.channel import ChannelType
from yuxi.channels.contract.dtos.common import Operator
from yuxi.channels.contract.errors import ValidationError
#: 主动深度探测超时毫秒数上限(与 Router 层 Pydantic schema ``le=30000`` 对齐)。
#: DTO 作为契约层单一事实源,内部调用方同样受此上界约束。
_PROBE_TIMEOUT_MS_MAX: int = 30000
@dataclass(frozen=True)
class HealthCheckResult:
"""健康检查结果。
描述渠道插件的轻量级健康探针结果,包括是否健康与可选错误信息,
作为 ``DoctorAdapter.checkConnectivity`` 方法的返回值PRD §4.0.4
核心方法 6健康检查
与 ``DoctorAdapter``深度诊断FR-17分离健康检查是轻量级探针
诊断是深度检查(含连通性、权限、配置项等)。
字段:
healthy: 是否健康。
message: 错误或状态信息(可选,健康时为 None
checked_at: 检查时间戳。
"""
healthy: bool
checked_at: datetime
message: str | None = None
@dataclass(frozen=True)
class SingleHealthQuery:
"""单渠道健康查询HLT-SINGLE
描述单渠道健康查询的输入,包括渠道类型与账户 ID。HLT-SINGLE 为纯读
聚合操作账户状态、熔断器状态、队列深度、插件状态、worker 状态),
不触发渠道 API 调用;主动深度探测由 HLT-PROBEPOST承担。
字段:
channel_type: 渠道类型。
account_id: 渠道账户 ID。
"""
channel_type: ChannelType
account_id: str
def __post_init__(self) -> None:
"""校验必填字段非空HLT-SINGLE @pre
``account_id`` 必须非空,在构造时即抛出 ``ValidationError``
adapter 不再做该校验INV-8 / 端口契约前置条件)。
"""
if not self.account_id:
raise ValidationError("account_id", "must not be empty")
@dataclass(frozen=True)
class SingleHealthResult:
"""单渠道健康结果HLT-SINGLE
聚合账户状态、熔断器状态、队列深度、插件状态等健康指标,供运维排障
定位单渠道健康问题。HLT-SINGLE 为纯读聚合,不含探测时间戳;主动
深度探测结果由 HLT-PROBEPOST的 ``ProbeResult`` 承载。
字段:
channel_type: 渠道类型。
account_id: 渠道账户 ID。
status: 健康状态。
plugin_state: 插件生命周期状态。
circuit_breaker_state: 熔断器状态。
queue_depth: 队列深度。
connection_pool_status: 连接池状态。
worker_status: worker 状态。
last_error: 最近错误信息(可选)。
"""
channel_type: str
account_id: str
status: str
plugin_state: str
circuit_breaker_state: str
queue_depth: int
connection_pool_status: str
worker_status: str
last_error: str | None = None
@dataclass(frozen=True)
class ProbeCmd:
"""主动探测命令HLT-PROBE
由 ``HealthCheckPort.probeChannelDeep`` 引用,通过插件
``ProbeableAdapter.probeDeep`` 执行深度探测,需记录操作人以满足审计要求。
字段:
channel_type: 渠道类型。
account_id: 渠道账户 ID。
operator: 操作人(审计用)。
probe_type: 探测类型(``connectivity`` / ``full``)。
timeout_ms: 超时毫秒数(默认 5000
"""
channel_type: ChannelType
account_id: str
operator: Operator
probe_type: Literal["connectivity", "full"]
timeout_ms: int = 5000
def __post_init__(self) -> None:
"""校验必填字段与业务规则HLT-PROBE @pre
``account_id`` 必须非空,``probe_type`` 必须为 ``connectivity`` 或
``full````timeout_ms`` 必须为正整数且不超过 30000与 Router 层
Pydantic schema ``le=30000`` 对齐,防御深度)。在构造时即抛出
``ValidationError``adapter 不再做该校验INV-8 / 端口契约前置条件)。
"""
if not self.account_id:
raise ValidationError("account_id", "must not be empty")
if self.probe_type not in ("connectivity", "full"):
raise ValidationError(
"probe_type",
f"probe_type must be connectivity or full, got {self.probe_type!r}",
)
if self.timeout_ms <= 0:
raise ValidationError("timeout_ms", "must be positive")
if self.timeout_ms > _PROBE_TIMEOUT_MS_MAX:
raise ValidationError(
"timeout_ms",
f"timeout_ms must not exceed {_PROBE_TIMEOUT_MS_MAX}, got {self.timeout_ms}",
)
@dataclass(frozen=True)
class ProbeResult:
"""主动探测结果HLT-PROBE
字段:
channel_type: 渠道类型。
account_id: 渠道账户 ID。
probe_type: 探测类型。
result: 探测结果(``reachable`` / ``unreachable`` / ``degraded``)。
probed_at: 探测时间戳。
latency_ms: 探测延迟毫秒数(可选,探测失败时为 None
details: 探测详情(可选)。
"""
channel_type: str
account_id: str
probe_type: str
result: Literal["reachable", "unreachable", "degraded"]
probed_at: datetime
latency_ms: int | None = None
details: dict[str, Any] | None = None