"""事务基础设施异常。 定义事务控制链路的稳定错误码与异常类型,全部继承自 ``yuxi.channels.contract.errors.base.Error``,复用 UnifiedError 协议 (``status_code`` / ``error_code`` / ``message`` / ``details`` / ``trace_id``), 不重新实现协议字段。 错误码: - ``TX_BEGIN_ERROR``:事务开启失败 - ``TX_COMMIT_ERROR``:事务提交失败 - ``TX_ROLLBACK_ERROR``:事务回滚失败 - ``TX_INACTIVE_ERROR``:事务已关闭时操作 HTTP 状态码:四个错误码均未注册到 ``CHANNEL_ERROR_STATUS_MAP``,基类 ``Error.status_code`` 查表未命中时返回 500。 诊断字段:每个异常携带 ``transaction_id`` 与 ``session_state``,通过覆写 ``to_dict()`` 纳入序列化结果;基类 ``details`` property 从 ``to_dict()`` 提取(排除 ``error_code`` / ``message`` / ``trace_id``),因此这两个字段 自动进入 ``details``。 """ from __future__ import annotations from typing import Any from yuxi.channels.contract.errors.base import Error class _TransactionError(Error): """事务异常内部基类。 为四个事务异常提供共享的 ``transaction_id`` / ``session_state`` 诊断字段, 覆写 ``to_dict()`` 将其纳入序列化结果。不直接实例化,由具体子类继承, 复用 ``Error`` 已实现的 UnifiedError 协议(``status_code`` / ``details``)。 """ def __init__( self, message: str, *, transaction_id: str = "", session_state: str = "", trace_id: str | None = None, ) -> None: super().__init__(message, trace_id=trace_id) self.transaction_id = transaction_id self.session_state = session_state def to_dict(self) -> dict[str, Any]: """序列化为字典,在基础字段外补充事务诊断字段。""" base = super().to_dict() base["transaction_id"] = self.transaction_id base["session_state"] = self.session_state return base class TransactionBeginError(_TransactionError): """事务开启失败。 在 ``TransactionContext.__aenter__`` 中 ``session.begin()`` 抛错时抛出, ``error_code`` 为 ``TX_BEGIN_ERROR``。 """ error_code = "TX_BEGIN_ERROR" class TransactionCommitError(_TransactionError): """事务提交失败。 在 ``commit()`` 或 ``__aexit__`` 提交阶段抛错时抛出, ``error_code`` 为 ``TX_COMMIT_ERROR``。 """ error_code = "TX_COMMIT_ERROR" class TransactionRollbackError(_TransactionError): """事务回滚失败。 在 ``rollback()`` 或 ``__aexit__`` 回滚阶段抛错时抛出, ``error_code`` 为 ``TX_ROLLBACK_ERROR``。 """ error_code = "TX_ROLLBACK_ERROR" class TransactionInactiveError(_TransactionError): """事务已关闭时操作。 在事务已提交/回滚后再次执行需要活动事务的操作时抛出, ``error_code`` 为 ``TX_INACTIVE_ERROR``。 """ error_code = "TX_INACTIVE_ERROR"