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

85 lines
3.1 KiB
Python
Raw Normal View History

"""领域事件 DTO。
定义跨层传递的领域事件值对象 ``EventPublisherPort`` 发布与订阅者消费
事件载荷为不可变值对象``dataclass(frozen=True)``不泄露领域实体引用
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from yuxi.channels.contract.dtos.outbox import OutboxStatus
from yuxi.channels.contract.errors import ValidationError
@dataclass(frozen=True)
class OutboxStateChangedEvent:
"""发件箱状态变更事件OBX-004
描述一条发件箱条目``OutboxEntry``的状态迁移由应用层在 outbox
状态机推进时``markSent`` / ``markFailed`` / ``markSuppressed`` /
``markSentUnconfirmed`` 产出 ``EventPublisherPort`` 分发给
订阅者状态值取自 ``OutboxStatus`` 枚举的字符串形式便于跨层序列化
与审计
字段
entry_id: 发件箱条目 ID``OutboxEntry.outbox_id``
old_state: 变更前状态``OutboxStatus`` 字符串值
new_state: 变更后状态``OutboxStatus`` 字符串值
reason: 变更原因如投递成功重试失败栅栏抑制等
occurred_at: 事件发生时间
"""
entry_id: str
old_state: OutboxStatus
new_state: OutboxStatus
reason: str
occurred_at: datetime
def __post_init__(self) -> None:
"""校验必填字段非空。
``entry_id`` / ``old_state`` / ``new_state`` / ``reason`` 必须非空
在构造时即抛出 ``ValidationError``避免空值事件传播到订阅者
INV-8
"""
if not self.entry_id:
raise ValidationError("entry_id", "must not be empty")
if not self.old_state:
raise ValidationError("old_state", "must not be empty")
if not self.new_state:
raise ValidationError("new_state", "must not be empty")
if not self.reason:
raise ValidationError("reason", "must not be empty")
@dataclass(frozen=True)
class OutboxEntryPurgedEvent:
"""发件箱条目被物理清理事件OBX-005
描述一批发件箱条目``OutboxEntry``被物理删除purge的事件
调度器定时清理 dead / sent 终态条目时产出 ``EventPublisherPort``
分发给订阅者``entry_ids`` 为本次被清理条目的业务 ID 列表供下游
做审计统计与缓存失效等处理
字段
entry_ids: 被物理清理的发件箱条目业务 ID 列表``OutboxEntry.outbox_id``
occurred_at: 事件发生时间
"""
entry_ids: tuple[str, ...]
occurred_at: datetime
def __post_init__(self) -> None:
"""校验 entry_ids 非空。
``entry_ids`` 必须为非空元组空列表的清理事件无意义在构造时即
抛出 ``ValidationError``避免空事件传播到订阅者INV-8
"""
if not self.entry_ids:
raise ValidationError("entry_ids", "must not be empty")
__all__ = ["OutboxStateChangedEvent", "OutboxEntryPurgedEvent"]