本次提交包含多项核心改进: 1. 新增微信公众号插件拉取传输模式配置,完善manifest与manifest加载逻辑 2. 新增运行态状态机与幂等冲突错误体系,补充错误映射与领域错误导出 3. 优化出站与入站上下文,新增幂等键、流式中断标记等字段 4. 完善发件箱仓储与模型,新增失败条目查询、投递原子语义字段 5. 修复签名验证阶段异常捕获逻辑,防御性处理内置NotImplementedError 6. 新增出站预算释放方法,完善机器人循环预算管控 7. 优化出站管道格式阶段,新增消息长度校验逻辑 8. 完善出站打字指示器阶段,新增重复启动防御与状态同步 9. 重构出站标记失败阶段,按源状态分支处理状态转换 10. 新增入站幂等过滤阶段,修复入站路由阶段空指针问题 11. 优化出站恢复扫描器,修复状态机调用与聚合根重建逻辑 12. 完善微信公众号适配器,新增类型校验与异常包装 13. 修复数据库事务回滚逻辑,简化不必要的显式回滚操作
147 lines
5.6 KiB
Python
147 lines
5.6 KiB
Python
"""传输层配置 DTO。
|
||
|
||
定义传输层相关的不可变值对象,包括轮询配置、流配置、传输配置、轮询结果、
|
||
流连接等。``TransportErrorCategory`` 类型定义于 ``errors.transport`` 模块,
|
||
此处通过 re-export 保持向后兼容的导入路径。所有 DTO 均为
|
||
``dataclass(frozen=True)``,仅依赖标准库,使用前向引用避免循环依赖。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from collections.abc import Awaitable, Callable
|
||
from dataclasses import dataclass
|
||
from typing import TYPE_CHECKING, Any
|
||
|
||
from yuxi.channels.contract.errors import ValidationError
|
||
from yuxi.channels.contract.errors.transport import (
|
||
TransportErrorCategory as TransportErrorCategory,
|
||
)
|
||
|
||
if TYPE_CHECKING:
|
||
from yuxi.channels.contract.errors.transport import TransportError
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class PollingConfig:
|
||
"""轮询模式配置。
|
||
|
||
描述长轮询/短轮询的超时与批量参数配置。
|
||
|
||
模式判定规则:
|
||
- ``long_poll_timeout_ms > 0`` 且 ``poll_interval_ms == 0``:长轮询模式
|
||
- ``poll_interval_ms > 0``:短轮询模式
|
||
- 两者都为 0:未配置,由装配层在使用时校验
|
||
|
||
字段:
|
||
long_poll_timeout_ms: 长轮询超时时间(毫秒),0 表示不启用长轮询。
|
||
poll_interval_ms: 短轮询间隔时间(毫秒),0 表示不启用短轮询。
|
||
max_batch_size: 单次轮询最大拉取消息数。
|
||
"""
|
||
|
||
long_poll_timeout_ms: int = 0
|
||
poll_interval_ms: int = 0
|
||
max_batch_size: int = 100
|
||
|
||
def __post_init__(self) -> None:
|
||
"""校验轮询模式配置合法性。
|
||
|
||
``long_poll_timeout_ms`` / ``poll_interval_ms`` 必须为非负整数,
|
||
``max_batch_size`` 必须为正整数。两者同时为 0 表示未配置,由装配层
|
||
在使用时校验模式合法性(INV-8)。
|
||
"""
|
||
if self.long_poll_timeout_ms < 0:
|
||
raise ValidationError(
|
||
"long_poll_timeout_ms",
|
||
"must be a non-negative integer",
|
||
)
|
||
if self.poll_interval_ms < 0:
|
||
raise ValidationError(
|
||
"poll_interval_ms",
|
||
"must be a non-negative integer",
|
||
)
|
||
if self.max_batch_size <= 0:
|
||
raise ValidationError("max_batch_size", "must be a positive integer")
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class StreamConfig:
|
||
"""流式连接配置。
|
||
|
||
描述流式传输(如 SSE/WebSocket)的心跳与连接超时参数。
|
||
|
||
字段:
|
||
heartbeat_interval_ms: 心跳发送间隔(毫秒),用于保活检测。
|
||
connect_timeout_ms: 连接建立超时时间(毫秒)。
|
||
"""
|
||
|
||
heartbeat_interval_ms: int = 30000
|
||
connect_timeout_ms: int = 10000
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class TransportConfig:
|
||
"""传输层全局配置。
|
||
|
||
描述传输层的超时、退避重试、优雅关闭等参数,支持热更新。
|
||
配置变更时无需重启进程,传输层运行时自动应用最新值。
|
||
|
||
字段:
|
||
stall_timeout_ms: 连接空闲超时时间(毫秒),超过此时间无数据传输视为停滞。
|
||
backoff_schedule: 重试退避调度序列(秒),按重试次数依次取值,超出后使用最后一个值。
|
||
backoff_jitter: 退避时间抖动比例(0-1),用于避免惊群效应。
|
||
max_restart_attempts: 最大重启尝试次数,``None`` 表示无限重启。
|
||
graceful_shutdown_timeout_s: 优雅关闭超时时间(秒)。
|
||
stream_reconnect_backoff_ms: StreamWorker 断线重连初始退避(毫秒,Task 10.3)。
|
||
指数退避基数,每次重连翻倍直到 ``stream_reconnect_max_backoff_ms``。
|
||
stream_reconnect_max_backoff_ms: StreamWorker 断线重连最大退避(毫秒,Task 10.3)。
|
||
指数退避上限,避免无限增长。
|
||
"""
|
||
|
||
stall_timeout_ms: int = 120000
|
||
backoff_schedule: tuple[float, ...] = (1.0, 2.0, 5.0, 10.0, 30.0)
|
||
backoff_jitter: float = 0.2
|
||
max_restart_attempts: int | None = None
|
||
graceful_shutdown_timeout_s: float = 10.0
|
||
stream_reconnect_backoff_ms: int = 1000
|
||
stream_reconnect_max_backoff_ms: int = 30000
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class PollResult:
|
||
"""轮询结果。
|
||
|
||
描述单次轮询操作的返回结果,三种互斥状态:
|
||
1. 正常返回:``messages`` 非空或空元组,``error`` 为 ``None``,``next_cursor`` 可选
|
||
2. 错误返回:``error`` 非空,``messages`` 为空,``next_cursor`` 为 ``None``
|
||
3. 空轮询(长轮询超时):``messages`` 为空,``error`` 为 ``None``,``next_cursor`` 保持不变
|
||
|
||
字段:
|
||
messages: 本次拉取到的消息列表(tuple 保证不可变)。
|
||
next_cursor: 下一轮询游标,``None`` 表示无更多数据。
|
||
error: 轮询过程中发生的错误,``None`` 表示成功。
|
||
"""
|
||
|
||
messages: tuple[dict[str, Any], ...] = ()
|
||
next_cursor: str | None = None
|
||
error: TransportError | None = None
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class StreamConnection:
|
||
"""流式连接句柄(P1 预留)。
|
||
|
||
封装已建立的流式连接的收发与关闭操作,用于统一 WebSocket / SSE 等
|
||
不同流式协议的接口。P1 阶段暂不实现,保留接口定义供后续扩展。
|
||
|
||
字段:
|
||
receive: 异步接收消息的回调函数。
|
||
send: 异步发送消息的回调函数。
|
||
close: 异步关闭连接的回调函数。
|
||
extra: 协议特定的扩展数据,如连接上下文、原始会话等。
|
||
"""
|
||
|
||
receive: Callable[[], Awaitable[dict[str, Any]]]
|
||
send: Callable[[dict[str, Any]], Awaitable[None]]
|
||
close: Callable[[], Awaitable[None]]
|
||
extra: Any = None
|