[062][调度模块]任务全生命周期管理 —— 从启动到追踪的完整闭环

简介: 本文详解调度模块任务全生命周期管理:涵盖启动/取消协调(ScheduleService)、三级数据聚合(DB+内存+运行态)、运行态安全校验及规格模式分页查询,实现高可用、强一致的任务闭环管控。(239字)

[062][调度模块]任务全生命周期管理 —— 从启动到追踪的完整闭环

本文章代码: gitee , gitcode , github

1. 任务启动与取消的核心协调器:ScheduleService

ScheduleService 作为应用层门面,协调 TaskRepository(持久化)和 ScheduleTaskManager(调度引擎)。

@Service
@RequiredArgsConstructor
public class ScheduleService {
   
    private final ScheduleTaskManager scheduleTaskManager;
    private final TaskRepository<?> taskRepository;

    public TaskExecutionDetails startTask(String taskCode) {
   
        Optional<? extends Task> taskOpt = taskRepository.findByTaskCode(taskCode);
        if (taskOpt.isPresent()) {
   
            Task task = taskOpt.get();
            scheduleTaskManager.createTask(task);  // 向调度器注册任务
            return buildDetails(task);             // 返回聚合详情
        }
        return null;
    }

    public TaskExecutionDetails cancelTask(String taskCode) {
   
        Optional<? extends Task> taskOpt = taskRepository.findByTaskCode(taskCode);
        if (taskOpt.isPresent()) {
   
            Task task = taskOpt.get();
            scheduleTaskManager.cancelTask(task.getTaskCode());  // 取消调度
            return buildDetails(task);
        }
        return null;
    }
}

关键设计:

  • 返回最新详情:启动/取消后立即返回 TaskExecutionDetails,方便 UI 即时反馈。
  • 容错处理:若 taskCode 不存在,返回 null(建议优化为抛出 TaskNotFoundException 或返回 Optional)。

2. 运行时详情聚合:buildDetails 的巧妙实现

private TaskExecutionDetails buildDetails(Task task) {
   
    // 1. 初始化 Builder,填充静态配置
    TaskExecutionDetails.TaskExecutionDetailsBuilder builder =
        TaskExecutionDetails.builder()
            .taskCode(task.getTaskCode())
            .classSimpleName(task.getClassSimpleName())
            .cron(task.getCron())
            .enabled(task.isEnabled())
            .description(task.getDescription())
            .metadata(MapUtils.unmodifiableMap(task.getMetadata()))
            .initialDelay(task.getInitialDelay())
            .maxExecutionCount(task.getMaxExecutionCount())
            .maxFailureCount(task.getMaxFailureCount())
            .dueDate(task.getDueDate());

    // 2. 覆盖内存中运行任务的实时配置(若任务正在运行)
    Task runningTask = scheduleTaskManager.getTask(task.getTaskCode());
    if (runningTask != null) {
   
        // ✅ 修正:必须复用 builder 实例,而非重新调用 builder()
        builder.taskCode(runningTask.getTaskCode())
               .classSimpleName(runningTask.getClassSimpleName())
               .cron(runningTask.getCron())
               .enabled(runningTask.isEnabled())
               .description(runningTask.getDescription())
               .metadata(MapUtils.unmodifiableMap(runningTask.getMetadata()))
               .initialDelay(runningTask.getInitialDelay())
               .maxExecutionCount(runningTask.getMaxExecutionCount())
               .maxFailureCount(runningTask.getMaxFailureCount())
               .dueDate(runningTask.getDueDate());
    }

    // 3. 填充最近一次执行状态(如运行中、成功、失败)
    TaskRuntimeData lastRuntimeData = 
        scheduleTaskManager.getLastTaskRuntimeData(task.getTaskCode());
    if (lastRuntimeData != null) {
   
        builder.taskStatus(lastRuntimeData.taskStatus())
               .lotNo(lastRuntimeData.lotNo())
               .totalCount(lastRuntimeData.totalCount())
               .totalFailureCount(lastRuntimeData.totalFailureCount())
               .startTime(lastRuntimeData.startTime())
               .endTime(lastRuntimeData.endTime())
               .message(lastRuntimeData.message())
               .throwable(lastRuntimeData.throwable());
    }
    return builder.build();
}

技术亮点:

  • 三级数据聚合:① 数据库持久化配置(基础)→ ② 内存运行实例(动态覆盖)→ ③ 最近执行状态(运行快照)。
  • 链式调用复用:通过复用 builder 变量,避免生成多个临时对象。

3. 运行态保护:修改/删除前的安全校验

JobEndpoint 中,更新或删除任务前必须检查是否正在运行:

@PutMapping("/{id}")
public ResponseEntity<JobVO> updateJob(@PathVariable Long id, @RequestBody JobUpdateDTO dto) {
   
    JobEntity job = jobService.findById(id);
    checkJobIsRunning(job.getTaskCode());  // 抛出异常若运行中
    BeanUtils.copyProperties(dto, job);
    return ResponseEntity.ok(JobVO.of(jobService.save(job)));
}

private void checkJobIsRunning(String taskCode) {
   
    if (scheduleTaskManager.isTaskRunning(taskCode)) {
   
        throw new ScheduleException("任务运行中,不能操作;请先取消任务");
    }
}

并发考量:此处存在 TOCTOU(Time-of-Check-Time-of-Use)问题,建议在 ScheduleTaskManager 层使用 ConcurrentHashMap 的原子操作或分布式锁(如 Redisson)。

4. 分页查询任务:规格模式的应用

@Data
public class JobQuery {
   
    private String taskCode;
    private String classSimpleName;
    private String description;

    public Specification<JobEntity> buildSpecification() {
   
        List<Specification<JobEntity>> specList = new ArrayList<>();
        specList.add(JobSpecification.taskCodeEqual(taskCode));
        specList.add(JobSpecification.classSimpleNameEqual(classSimpleName));
        specList.add(JobSpecification.descriptionLike(description));
        return specList.stream()
            .filter(Objects::nonNull)
            .reduce(Specification::and)
            .orElse((root, query, cb) -> cb.conjunction());  // 无条件时返回恒真条件
    }
}

技术亮点

  • 流式组合:通过 reduce(Specification::and) 链式拼接所有非空条件。
  • 默认全查询:若查询条件为空,返回 cb.conjunction()(即 WHERE 1=1),避免 null 异常。
目录
相关文章
人工智能 缓存 前端开发
6328 20
人工智能 JavaScript 开发工具
3323 5
缓存 JavaScript Shell
1573 2
开发工具 Swift git
1137 1
Shell API 调度
885 2
|
13天前
|
存储 弹性计算 缓存
阿里云服务器租赁费用:新版租赁收费标准及活动报价参考
本文更新了2026年阿里云全系列云服务器租赁活动报价,所有特惠资源均可前往阿里云活动中心选购,整体覆盖从个人入门到企业级高性能场景的全梯度需求。其中轻量应用服务器主打极致性价比,2核2G峰值200M带宽配置每日10点、15点限时抢购价仅38元/年,2核4G配置379元/年起;高性价比的经济型e实例、通用算力型u2i实例覆盖2核4G至4核32G全档位,适配开发测试与中小型企业业务;搭载英特尔至强6处理器的第九代c9i企业级实例算力较上代提升20%,支撑高并发生产环境,不同实例规格价差清晰,用户可根据自身业务负载与预算灵活选型。
2138 121
阿里云服务器租赁费用:新版租赁收费标准及活动报价参考
|
14天前
|
人工智能 程序员 API
Codex 接入 DeepSeek-V4-Flash:还能补上识图,提供两套方案
Codex 接入 DeepSeek-V4-Flash 怎么配?本文覆盖 CLI 与桌面端,再用 qwen3-vl-flash 补识图,两套方案可直接照做
1796 13
安全 机器人 API
641 2
缓存 人工智能 算法
731 1

热门文章

最新文章