From 67d42fc2467a6e0f788ad35a3825ff5a860867fa Mon Sep 17 00:00:00 2001 From: Kris <2893855659@qq.com> Date: Wed, 24 Jun 2026 21:52:02 +0800 Subject: [PATCH] =?UTF-8?q?refactor(scheduler/exceptions):=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E5=BC=82=E5=B8=B8=E5=9F=BA=E7=B1=BB=E4=B8=8E=E5=AD=90?= =?UTF-8?q?=E7=B1=BB=E7=9A=84=E9=94=99=E8=AF=AF=E7=A0=81=E5=92=8C=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 为SchedulerError基类新增error_code类变量、trace_id参数和to_dict序列化方法 2. 为所有异常子类补充对应的业务错误码 3. 优化异常的字符串展示格式,增加error_code前缀 --- backend/package/yuxi/scheduler/exceptions.py | 41 +++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/backend/package/yuxi/scheduler/exceptions.py b/backend/package/yuxi/scheduler/exceptions.py index bdfcdd3d..ba00bf73 100644 --- a/backend/package/yuxi/scheduler/exceptions.py +++ b/backend/package/yuxi/scheduler/exceptions.py @@ -35,22 +35,48 @@ class SchedulerError(Exception): 所有本上下文抛出的异常都应继承此类,最外层统一捕获后映射为 HTTP 响应。 ``status_code`` 作为异常到 HTTP 状态码的映射依据,子类按需覆盖。 + ``error_code`` 作为稳定错误码,子类以类变量覆盖,用于驱动协议响应与日志关联。 + ``trace_id`` 用于跨链路追踪关联。 """ status_code: int = 500 + error_code: str = "SCHEDULER_ERROR" def __init__( self, message: str, *, details: dict[str, Any] | None = None, + trace_id: str | None = None, ) -> None: + """初始化异常实例。 + + 参数: + message: 人类可读错误信息。 + details: 业务字段字典,默认空字典。 + trace_id: 调用链路追踪 ID,用于跨链路关联。 + """ super().__init__(message) self.message = message self.details = details or {} + self.trace_id = trace_id + + def to_dict(self) -> dict[str, Any]: + """序列化为字典,便于跨层传递、日志记录与 API 响应。 + + 返回 ``error_code`` / ``message`` / ``trace_id`` 三个基础字段, + 并展开 ``details`` 中的业务字段。 + """ + return { + "error_code": self.error_code, + "message": self.message, + "trace_id": self.trace_id, + **self.details, + } def __str__(self) -> str: - return self.message + """返回 ``[error_code] message`` 格式的字符串表示。""" + return f"[{self.error_code}] {self.message}" # ─── 业务规则异常 ────────────────────────────────────────────────────────── @@ -64,6 +90,7 @@ class SchedulerValidationError(SchedulerError, ValueError): """ status_code = 400 + error_code = "VALIDATION_ERROR" class InvalidCronExpressionError(SchedulerValidationError): @@ -73,6 +100,8 @@ class InvalidCronExpressionError(SchedulerValidationError): ``expression`` / ``field`` / ``reason`` 等定位信息。 """ + error_code = "INVALID_CRON" + class SchedulerPayloadTooLargeError(SchedulerValidationError): """任务 payload 超过大小限制。 @@ -82,6 +111,7 @@ class SchedulerPayloadTooLargeError(SchedulerValidationError): """ status_code = 413 + error_code = "PAYLOAD_TOO_LARGE" class HandlerNotFoundError(SchedulerValidationError): @@ -92,6 +122,8 @@ class HandlerNotFoundError(SchedulerValidationError): 归入 ``SchedulerValidationError``。``details`` 可携带 ``handler_key``。 """ + error_code = "HANDLER_NOT_FOUND" + # ─── 实体不存在 ────────────────────────────────────────────────────────── @@ -104,6 +136,7 @@ class SchedulerEntityNotFoundError(SchedulerError): """ status_code = 404 + error_code = "NOT_FOUND" # ─── 权限 ──────────────────────────────────────────────────────────────── @@ -117,6 +150,7 @@ class SchedulerPermissionDeniedError(SchedulerError): """ status_code = 403 + error_code = "PERMISSION_DENIED" # ─── 冲突 ──────────────────────────────────────────────────────────────── @@ -130,6 +164,7 @@ class SchedulerConflictError(SchedulerError): """ status_code = 409 + error_code = "CONFLICT" class DuplicateHandlerError(SchedulerConflictError): @@ -139,6 +174,8 @@ class DuplicateHandlerError(SchedulerConflictError): ``details`` 可携带 ``handler_key`` / ``existing_class``。 """ + error_code = "DUPLICATE_HANDLER" + class TaskStatusTransitionError(SchedulerConflictError): """任务状态机非法转换。 @@ -146,3 +183,5 @@ class TaskStatusTransitionError(SchedulerConflictError): 由任务状态机在不允许的转换路径上抛出(如从 ``succeeded`` 转回 ``running``)。 ``details`` 可携带 ``from_state`` / ``to_state`` / ``allowed_transitions``。 """ + + error_code = "STATUS_TRANSITION_INVALID"