本次提交包含多项代码优化与规范修正: 1. 文档与注释优化:修正注释术语、补充注解与FR编号 2. 代码格式调整:统一空格、换行与缩进规范 3. 类型与接口完善:补充__all__导出、修正返回类型注解 4. 错误处理增强:新增领域错误类与校验逻辑 5. 依赖与导入调整:修复路径引用、统一时区导入 6. 协议与契约更新:完善接口文档与一致性注解
168 lines
5.8 KiB
Python
168 lines
5.8 KiB
Python
"""健康检查结果 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-PROBE(POST)承担。
|
||
|
||
字段:
|
||
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-PROBE(POST)的 ``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
|