package com.ruoyi.common.core.service;
import com.ruoyi.common.core.service.dto.VisitScheduleRollResultDto;
import java.util.List;
/**
* 循环任务组「轮次滚动」能力的预留接口(第 9 步)。
*
*
为什么这个接口是"粗粒度"的(重要设计说明)
* 任务组滚动的核心动作要做一次 {@code ServiceSubtask} 的全字段深拷贝:
*
* ServiceSubtask copy = JSON.parseObject(JSON.toJSONString(src), ServiceSubtask.class);
* copy.setId(null); copy.setSenduuid(null); copy.setResult(null); ...
*
* 而 {@code ServiceSubtask} 有 116 个字段。
*
* 如果为了"把逻辑搬进新模块"而在模块间传一个 116 字段的 DTO,字段映射本身就是巨大风险面,
* 且换不来任何收益 —— 全字段拷贝的语义由 JSON 序列化保证,不需要逐字段搬运。
*
* 所以本接口刻意切成两个动作,把"原子性"留在实现侧:
*
* - {@link #selectActiveCycleSchedules(int)} —— 查一批待评估的循环计划;
* - {@link #rollOneSchedule(Long)} —— 滚动单个计划(整个动作原子完成,含深拷贝与推进)。
*
* 调用方({@code ruoyi-inhospvisit} 的 {@code TaskGroupCycleRoller})
* 负责"批次上限 + 逐条 try/catch + 计数与日志"这部分编排逻辑。
*
* 这与其它端口({@code VisitTaskCreateApi} 等)的粒度不同,是有意的:
* 那些端口的对象字段少、映射可控;这里的对象有 116 个字段、且语义是"整体克隆"。
*
*
与 {@code ServiceTaskScheduleServiceImpl#rollCycleTasks} 的关系
* {@code rollCycleTasks} 的实现本次刻意保留在 smartor 不动(它仍被
* {@code RyTask.rollTaskGroupCycle} 调用,而改调用点在第 10 步)。
* 本接口的实现(过渡 Bridge)与它共享同一套底层能力(同一个 Mapper、同一份深拷贝语义),
* 不复制业务逻辑;等到第 10 步把调用点切过来后,{@code rollCycleTasks} 才退役。
*
* ⚠️ 过渡期禁止双跑
* 第 9 步做完后,「老的 {@code rollCycleTasks}」与「新的 {@code TaskGroupCycleRoller}」
* 不能同时被调度 —— 两边都会"推进轮次 + 新建 subtask",双跑会造成重复轮次。
* 第 10 步会把 {@code RyTask} 的方法体切到新路径;在那之前,新路径只被自检程序调用。
*/
public interface ScheduleRollPort {
/**
* 查一批待评估的循环计划(原 {@code ServiceTaskScheduleMapper#selectActiveCycleSchedules})。
*
* 该查询自身的条件({@code schedule_style = 1}、{@code max_loop_count} 上限等)在
* smartor 的 XML 里,本次照抄不动,由实现侧保证。
*
* @param limit 批次上限(原实现固定 200)
* @return 计划ID列表;无数据返回空列表
*/
List selectActiveCycleSchedules(int limit);
/**
* 滚动单个计划:若"本轮已全部结束"则推进到下一轮并克隆 subtask。
*
* 逐行对应原 {@code ServiceTaskScheduleServiceImpl#rollOneSchedule}(L196-280),包括:
*
* - 上限校验({@code maxLoopCount})与"再开一轮是否超限"的判定;
* - 本轮是否全部结束({@code countActiveByScheduleIdAndLoop});
* - 拉本轮 subtask 作克隆模板 + 计划明细按 seq 索引;
* - 推进步长({@code scheduleTimeNum/Unit})合法性校验;
* - 逐条克隆(全字段深拷贝 + 清 6 个字段 + 按 detail 覆盖模板 + 推进时间)并落库;
* - 复制 {@code service_subtask_preachform} 行;
* - 推进 schedule 的 {@code current_loop_count / current_seq / next_seq / next_execute_time}。
*
* 整个动作必须在实现侧一次性完成(含事务),不能拆成"取模板→改→存"三步跨模块调用。
*
* @param scheduleId 计划ID
* @return 滚动结果({@code rolled=false} 时 {@code skipReason} 说明原因)
*/
VisitScheduleRollResultDto rollOneSchedule(Long scheduleId);
}