本次提交完成了定时任务调度限界上下文的全量基础架构搭建,包括: 1. 基于六边形架构的完整分层(core/use_cases/framework/adapters/infrastructure) 2. 任务调度核心领域模型、端口契约与校验工具 3. 持久化适配器层与SQLAlchemy仓储实现 4. 调度运行时核心组件(handler注册表、执行引擎) 5. 内置维护型任务handler(日志清理、幂等记录清理) 6. 全局异常处理器与PostgreSQL表结构适配 7. ARQ worker调度任务集成与启动装配逻辑
149 lines
5.5 KiB
Python
149 lines
5.5 KiB
Python
"""定时任务调度限界上下文的异常层次。
|
||
|
||
设计原则(见设计方案 §8.1):
|
||
|
||
- **根异常 + 分层异常,一个文件**:保留 ``SchedulerError`` 根异常,按层内聚子异常。
|
||
- **统一兜底**:所有异常继承 ``SchedulerError``,最外层(Router / 全局异常处理器)统一捕获。
|
||
- **``status_code`` 作为 HTTP 映射依据**:子类按需覆盖类级属性,无需自定义 ``__init__``。
|
||
|
||
本文件位于包根目录(非 ``core/`` 下),因为异常被所有层共享(core / use_cases / framework /
|
||
adapters),放在根目录便于统一导入路径。
|
||
|
||
异常层次:
|
||
|
||
::
|
||
|
||
SchedulerError (500) # 根异常
|
||
├── SchedulerValidationError (400, ValueError) # 业务规则校验失败
|
||
│ ├── InvalidCronExpressionError # cron 表达式非法
|
||
│ ├── SchedulerPayloadTooLargeError (413) # payload 超过大小限制
|
||
│ └── HandlerNotFoundError # 找不到 handler
|
||
├── SchedulerEntityNotFoundError (404) # 领域实体不存在
|
||
├── SchedulerPermissionDeniedError (403) # 权限不足
|
||
└── SchedulerConflictError (409) # 资源冲突
|
||
├── DuplicateHandlerError # handler 重复注册
|
||
└── TaskStatusTransitionError # 任务状态机非法转换
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
|
||
class SchedulerError(Exception):
|
||
"""定时任务调度限界上下文根异常。
|
||
|
||
所有本上下文抛出的异常都应继承此类,最外层统一捕获后映射为 HTTP 响应。
|
||
``status_code`` 作为异常到 HTTP 状态码的映射依据,子类按需覆盖。
|
||
"""
|
||
|
||
status_code: int = 500
|
||
|
||
def __init__(
|
||
self,
|
||
message: str,
|
||
*,
|
||
details: dict[str, Any] | None = None,
|
||
) -> None:
|
||
super().__init__(message)
|
||
self.message = message
|
||
self.details = details or {}
|
||
|
||
def __str__(self) -> str:
|
||
return self.message
|
||
|
||
|
||
# ─── 业务规则异常 ──────────────────────────────────────────────────────────
|
||
|
||
|
||
class SchedulerValidationError(SchedulerError, ValueError):
|
||
"""调度业务规则校验失败。
|
||
|
||
同时继承 ``ValueError`` 以兼容 Pydantic 的 ``field_validator`` 与 ``raise ValueError(...)``
|
||
习惯写法(在 dataclass 薄校验中可直接 ``raise SchedulerValidationError(...)``)。
|
||
"""
|
||
|
||
status_code = 400
|
||
|
||
|
||
class InvalidCronExpressionError(SchedulerValidationError):
|
||
"""cron 表达式非法。
|
||
|
||
由 cron 解析器在表达式语法错误或字段越界时抛出。``details`` 可携带
|
||
``expression`` / ``field`` / ``reason`` 等定位信息。
|
||
"""
|
||
|
||
|
||
class SchedulerPayloadTooLargeError(SchedulerValidationError):
|
||
"""任务 payload 超过大小限制。
|
||
|
||
由 payload 校验器在序列化后字节数超阈值时抛出。``details`` 可携带
|
||
``size`` / ``limit`` / ``unit`` 等量化信息。
|
||
"""
|
||
|
||
status_code = 413
|
||
|
||
|
||
class HandlerNotFoundError(SchedulerValidationError):
|
||
"""找不到对应的任务 handler。
|
||
|
||
由 handler 注册表在按 key 查找 handler 未命中时抛出。虽然名字像 404,
|
||
但语义上属于"调度配置校验失败"(任务引用了未注册的 handler),按 spec
|
||
归入 ``SchedulerValidationError``。``details`` 可携带 ``handler_key``。
|
||
"""
|
||
|
||
|
||
# ─── 实体不存在 ──────────────────────────────────────────────────────────
|
||
|
||
|
||
class SchedulerEntityNotFoundError(SchedulerError):
|
||
"""调度领域实体不存在。
|
||
|
||
统一覆盖任务 / 任务执行记录 / handler 注册项等实体不存在场景。
|
||
具体实体类型由 ``message`` 描述,``details`` 可携带 ``entity_type`` / ``identifier``。
|
||
"""
|
||
|
||
status_code = 404
|
||
|
||
|
||
# ─── 权限 ────────────────────────────────────────────────────────────────
|
||
|
||
|
||
class SchedulerPermissionDeniedError(SchedulerError):
|
||
"""调度操作权限不足。
|
||
|
||
由权限校验器在当前用户/角色无权执行调度操作时抛出。
|
||
``details`` 可携带 ``action`` / ``resource`` / ``principal``。
|
||
"""
|
||
|
||
status_code = 403
|
||
|
||
|
||
# ─── 冲突 ────────────────────────────────────────────────────────────────
|
||
|
||
|
||
class SchedulerConflictError(SchedulerError):
|
||
"""调度资源冲突。
|
||
|
||
表示写操作因唯一约束冲突或状态竞争无法完成(如 handler 重复注册、
|
||
任务状态机非法转换等)。
|
||
"""
|
||
|
||
status_code = 409
|
||
|
||
|
||
class DuplicateHandlerError(SchedulerConflictError):
|
||
"""handler 重复注册。
|
||
|
||
由 handler 注册表在以已存在的 key 再次注册时抛出。
|
||
``details`` 可携带 ``handler_key`` / ``existing_class``。
|
||
"""
|
||
|
||
|
||
class TaskStatusTransitionError(SchedulerConflictError):
|
||
"""任务状态机非法转换。
|
||
|
||
由任务状态机在不允许的转换路径上抛出(如从 ``succeeded`` 转回 ``running``)。
|
||
``details`` 可携带 ``from_state`` / ``to_state`` / ``allowed_transitions``。
|
||
"""
|