[061][调度模块]领域驱动的任务调度架构设计与分层实践

[061][调度模块]领域驱动的任务调度架构设计与分层实践

本文章代码: gitee , gitcode , github

1. 整体架构蓝图

该模块采用六边形架构思想,将核心领域(调度、日志)与基础设施(数据库、Web)解耦。核心设计决策如下:

  • 任务定义与运行时分离:JobEntity 作为持久化配置,ScheduleTaskManager 管理内存中的执行实例,通过 Task 接口统一抽象。
  • 事件驱动的日志记录:状态变更事件异步触发日志持久化,避免阻塞调度主流程。
  • 规格模式(Specification):动态查询条件组合,避免冗长的 JPQL 拼接。
┌─────────────────────────────────────────────────────────────┐
│                    表示层 (Web)                             │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐ │
│  │ JobEndpoint  │  │ScheduleEndpoint│  │ JobLogEndpoint  │ │
│  └──────────────┘  └──────────────┘  └──────────────────┘ │
└─────────────────────────┬───────────────────────────────────┘
                          │ DTO/VO 转换
┌─────────────────────────▼───────────────────────────────────┐
│                    应用服务层 (Service)                      │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐ │
│  │  JobService  │  │ScheduleService│  │  JobLogService  │ │
│  └──────────────┘  └──────────────┘  └──────────────────┘ │
└─────────────────────────┬───────────────────────────────────┘
                          │ 领域接口
┌─────────────────────────▼───────────────────────────────────┐
│                    领域层 (Domain)                          │
│  ┌────────────────────────────────────────────────────────┐ │
│  │  interface Task  ◄─── implements  ──── JobEntity      │ │
│  │  interface TaskRepository  ◄─── implements ────       │ │
│  │            DatabaseTaskRepository (适配 JPA)          │ │
│  │  interface ChangeStatusEventConsumer ◄─── implements  │ │
│  │            JobLogEventConsumer (事件监听)             │ │
│  └────────────────────────────────────────────────────────┘ │
└─────────────────────────┬───────────────────────────────────┘
                          │ JPA
┌─────────────────────────▼───────────────────────────────────┐
│                    基础设施层 (Infrastructure)               │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐ │
│  │ JobRepository│  │JobLogRepository│  │ ScheduleTask    │ │
│  │  (JPA)       │  │   (JPA)       │  │   Manager       │ │
│  └──────────────┘  └──────────────┘  └──────────────────┘ │
└─────────────────────────────────────────────────────────────┘

2. 核心领域模型:Task 接口与 JobEntity 实现

技术亮点:接口统一 + 多态持久化

Task 接口定义了调度器所需的所有配置方法,JobEntity 通过实现该接口,既可作为 JPA 实体,又能直接注入调度管理器。

// 调度核心定义的任务契约
public interface Task {
    String getTaskCode();
    String getClassSimpleName();
    String getCron();
    boolean isEnabled();
    String getDescription();
    Map<String, String> getMetadata();
    Duration getInitialDelay();
    Integer getMaxFailureCount();
    Integer getMaxExecutionCount();
    Instant getDueDate();
}

// 领域实体同时实现接口与 JPA 注解
@Data
@Entity
@Table(name = "feat_job")
public class JobEntity extends BaseStatusEntity implements Task {
    @Column(length = 64, unique = true, updatable = false)
    private String taskCode;
    
    @Column(length = 64)
    private String classSimpleName;
    
    @Column(length = 64)
    private String cron;
    
    @JdbcTypeCode(SqlTypes.JSON)  // ✅ 利用 Hibernate 6 的 JSON 映射
    @Column(columnDefinition = "json")
    private Map<String, String> metadata;
    
    // ... 其他字段
    
    @Override
    public boolean isEnabled() {
        // 利用父类状态字段实现软删除 + 预留双重语义
        return Objects.equals(getDataStatus(), DataStatusEnum.NORMAL)
                || Objects.equals(getDataStatus(), DataStatusEnum.RESERVED);
    }
}

设计精要:

  • JSON 元数据:@JdbcTypeCode(SqlTypes.JSON) 自动序列化 Map 为 JSON 列,支持灵活扩展而无需 DDL 变更。
  • 状态语义:NORMAL 为正常启用,RESERVED 为保留(可被特殊逻辑触发),DELETED 为逻辑删除,丰富了生命周期管理。

3. 仓库适配层:DatabaseTaskRepository 的防腐作用

技术亮点:适配器模式隔离 ORM 依赖

@Service
@RequiredArgsConstructor
public class DatabaseTaskRepository implements TaskRepository<JobEntity> {
    private final JobRepository jobRepository;  // Spring Data JPA
    
    @Override
    public Optional<JobEntity> findByTaskCode(String taskCode) {
        return jobRepository.findByTaskCode(taskCode);
    }
    
    @Override
    public List<JobEntity> findAll() {
        return jobRepository.findAll();
    }
}

通过实现 TaskRepository 接口,上层 ScheduleService 完全不知晓 JPA 的存在。若将来迁移至 MyBatis 或 Redis,只需替换该适配类,业务逻辑零修改。

4. 不可变数据传输:Record + Builder 模式

TaskExecutionDetails 使用 @Builder 注解构建不可变对象,聚合任务定义与运行时状态:

@Builder
public record TaskExecutionDetails(
    String taskCode,          // 任务标识
    String classSimpleName,   // 执行类
    String cron,              // 调度表达式
    boolean enabled,          // 是否启用
    String description,       // 描述
    Map<String, String> metadata,  // 扩展属性(不可变视图)
    Duration initialDelay,
    Integer maxFailureCount,
    Integer maxExecutionCount,
    Instant dueDate,
    // 以下为运行时动态数据
    TaskStatusEnum taskStatus,
    String lotNo,
    int totalCount,
    int totalFailureCount,
    Instant startTime,
    Instant endTime,
    String message,
    Throwable throwable
) {}

技术亮点:

  • Record 不可变性:天然线程安全,适合多线程环境下的数据传递。
  • Builder 模式:支持部分字段构建,结合 MapUtils.unmodifiableMap 保证元数据只读。
posted @ 2026-08-17 08:33  杨运交  阅读(1)  评论(0)    收藏  举报