ForcePilot/backend/package/yuxi/channels/contract/dtos/ack.py

82 lines
2.4 KiB
Python
Raw Normal View History

"""分阶段 ACK DTO。
定义分阶段 ACKFR-24的枚举与不可变值对象包括 ACK 策略ACK 阶段
ACK 决策所有枚举继承 ``str, Enum`` 以支持 JSON 序列化DTO 均为
``dataclass(frozen=True)``仅依赖标准库用于入站消息的分阶段 ACK
决策与幂等控制
"""
from __future__ import annotations
from dataclasses import dataclass
from enum import StrEnum
from typing import Literal
from yuxi.channels.contract.errors import ValidationError
class AckPolicy(StrEnum):
"""ACK 策略。
标识入站消息的 ACK 时机用于控制 ACK 与消息处理流程的耦合关系
继承 ``str, Enum`` 以支持 JSON 序列化与字符串比较
取值
AFTER_RECORD: 消息记录后 ACK
AFTER_AGENT_DISPATCH: Agent 分发后 ACK
AFTER_PERSIST: 持久化投递后 ACK
MANUAL: 手动 ACK
"""
AFTER_RECORD = "after_record"
AFTER_AGENT_DISPATCH = "after_agent_dispatch"
AFTER_PERSIST = "after_persist"
MANUAL = "manual"
class AckStage(StrEnum):
"""ACK 阶段。
标识 ACK 决策所属的处理阶段用于分阶段 ACK 的状态机推进继承
``str, Enum`` 以支持 JSON 序列化与字符串比较
取值
RECORD: 记录阶段
DISPATCH: 分发阶段
PERSIST: 持久化阶段
MANUAL: 手动阶段
"""
RECORD = "record"
DISPATCH = "dispatch"
PERSIST = "persist"
MANUAL = "manual"
@dataclass(frozen=True)
class AckDecision:
"""ACK 决策FR-24
描述一次 ACK 决策的结果包括决策动作所属阶段与幂等键用于
分阶段 ACK 的决策传递与幂等控制
字段
decision: 决策动作ack | nack | retry | pending
stage: ACK 阶段
idempotency_key: 幂等键可选
"""
decision: Literal["ack", "nack", "retry", "pending"]
stage: AckStage
idempotency_key: str | None = None
def __post_init__(self) -> None:
"""校验 decision 取值合法。
``decision`` 必须为 ``ack`` / ``nack`` / ``retry`` / ``pending`` 之一在构造时
即抛出 ``ValidationError``避免非法决策动作导致 ACK 状态机推进
异常INV-8
"""
if self.decision not in ("ack", "nack", "retry", "pending"):
raise ValidationError("decision", "must be one of ack, nack, retry, pending")