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

98 lines
3.2 KiB
Python
Raw Normal View History

"""栅栏 DTO。
定义并发回复栅栏相关的不可变值对象包括栅栏裁决栅栏代际与栅栏
上下文所有 DTO 均为 ``dataclass(frozen=True)``仅依赖标准库
用于并发回复栅栏的代际控制与过期裁决FR-23
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from yuxi.channels.contract.errors import ValidationError
@dataclass(frozen=True)
class FenceVerdict:
"""栅栏裁决。
描述栅栏对一次回复的过期裁决包括是否过期当前代际与可选的
过期代际用于决定是否抑制过期回复
字段
is_stale: 是否过期
current_generation: 当前代际
stale_generation: 过期代际可选
"""
is_stale: bool
current_generation: int
stale_generation: int | None = None
@dataclass(frozen=True)
class FenceGeneration:
"""栅栏代际。
描述会话的栅栏代际状态包括当前代际与可见代际用于代际比较与
过期判定
字段
conversation_id: 会话 ID
current_generation: 当前代际
visible_generation: 可见代际
"""
conversation_id: str
current_generation: int
visible_generation: int
def __post_init__(self) -> None:
"""校验 conversation_id 非空与代际非负。
``conversation_id`` 必须非空``current_generation``
``visible_generation`` 必须非负在构造时即抛出 ``ValidationError``
避免空会话 ID 或负代际导致栅栏代际比较失效INV-8 / FR-23
"""
if not self.conversation_id:
raise ValidationError("conversation_id", "must not be empty")
if self.current_generation < 0:
raise ValidationError("current_generation", "must not be negative")
if self.visible_generation < 0:
raise ValidationError("visible_generation", "must not be negative")
@dataclass(frozen=True)
class FenceContext:
"""栅栏上下文。
描述栅栏的执行上下文包括会话 ID代际起始时间与 TTL用于
栅栏生命周期管理与过期清理
字段
conversation_id: 会话 ID
generation: 代际
started_at: 起始时间
ttl_seconds: TTL默认 120与配置项 ``fence_ttl_seconds`` 一致
"""
conversation_id: str
generation: int
started_at: datetime
ttl_seconds: int = 120
def __post_init__(self) -> None:
"""校验 conversation_id 非空、generation 非负与 ttl_seconds 为正整数。
``conversation_id`` 必须非空``generation`` 必须非负``ttl_seconds``
必须为正整数在构造时即抛出 ``ValidationError``避免空会话 ID
代际或非正 TTL 导致栅栏生命周期管理失效INV-8 / FR-23
"""
if not self.conversation_id:
raise ValidationError("conversation_id", "must not be empty")
if self.generation < 0:
raise ValidationError("generation", "must not be negative")
if self.ttl_seconds <= 0:
raise ValidationError("ttl_seconds", "must be a positive integer")