package cn.iocoder.yudao.module.mes.service.pro.bagcode;
|
|
import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeGenerateTaskMapper;
|
import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeGenerateTaskStatusEnum;
|
import cn.iocoder.yudao.module.mes.framework.bagcode.MesProBagCodeGenerateTaskRegistry;
|
import jakarta.annotation.Resource;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Component;
|
|
import java.time.LocalDateTime;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
/**
|
* 袋码生成任务执行器
|
* <p>
|
* 在后台线程内完成分段生成,并负责:回写进度、响应取消、失败/取消后清理半成品。
|
*/
|
@Slf4j
|
@Component
|
public class MesProBagCodeGenerateRunner {
|
|
@Resource
|
private MesProBagCodeGenerateTaskMapper taskMapper;
|
@Resource
|
private MesProBagCodeBatchGenerator generator;
|
@Resource
|
private MesProBagCodeGenerateCleaner cleaner;
|
@Resource
|
private MesProBagCodeGenerateTaskRegistry registry;
|
|
/**
|
* 执行生成任务(由线程池调用,勿在请求线程内直接调用)
|
*
|
* @param taskId 任务编号
|
* @param spec 生成参数
|
*/
|
public void run(Long taskId, MesProBagCodeGenerateSpec spec) {
|
// 取消标记在提交时已注册,这里只取用;取不到说明注册环节被绕过,补一个以保证取消可用
|
AtomicBoolean cancelFlag = registry.get(taskId);
|
if (cancelFlag == null) {
|
cancelFlag = registry.register(taskId);
|
}
|
try {
|
taskMapper.updateStatus(taskId, MesProBagCodeGenerateTaskStatusEnum.RUNNING.getStatus(),
|
null, null);
|
int finished = generator.generate(spec, taskId, cancelFlag).finishedCount();
|
// 最后一段写入后、任务收尾前才收到取消:仍按取消处理,保证"取消后无半成品"
|
if (cancelFlag.get()) {
|
throw new MesProBagCodeBatchGenerator.CancelledException();
|
}
|
taskMapper.updateProgress(taskId, finished);
|
taskMapper.updateStatus(taskId, MesProBagCodeGenerateTaskStatusEnum.FINISHED.getStatus(),
|
null, LocalDateTime.now());
|
log.info("[run][生成任务 {} 完成,共 {} 条袋码]", taskId, finished);
|
} catch (MesProBagCodeBatchGenerator.CancelledException e) {
|
cleanup(taskId, spec.uuid());
|
taskMapper.updateStatus(taskId, MesProBagCodeGenerateTaskStatusEnum.CANCELED.getStatus(),
|
null, LocalDateTime.now());
|
log.info("[run][生成任务 {} 已取消]", taskId);
|
} catch (Exception e) {
|
cleanup(taskId, spec.uuid());
|
taskMapper.updateStatus(taskId, MesProBagCodeGenerateTaskStatusEnum.FAILED.getStatus(),
|
truncateError(e), LocalDateTime.now());
|
log.error("[run][生成任务 {} 生成失败]", taskId, e);
|
} finally {
|
registry.unregister(taskId);
|
registry.release();
|
}
|
}
|
|
/**
|
* 清理半成品:清理失败只记录日志,不能影响任务终态回写,否则任务会一直挂在"生成中"
|
*/
|
private void cleanup(Long taskId, String uuid) {
|
try {
|
cleaner.cleanup(uuid);
|
} catch (Exception e) {
|
log.error("[cleanup][生成任务 {} 半成品清理失败,uuid={}]", taskId, uuid, e);
|
}
|
}
|
|
private String truncateError(Exception e) {
|
String message = e.getMessage();
|
if (message == null || message.isBlank()) {
|
message = e.getClass().getSimpleName();
|
}
|
return message.length() > 500 ? message.substring(0, 500) : message;
|
}
|
|
}
|