package cn.iocoder.yudao.module.mes.job.pro; import cn.iocoder.yudao.module.mes.service.pro.qrexport.MesProQrExportTaskService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; /** * 二维码导出临时文件清理 *

* 大批量导出的临时 ZIP 可达上 GB,正常下载完成后即删,本任务只兜底两类残留: *

    *
  1. 下载中断或生成完成后始终未下载的文件,超过保留期后删除;
  2. *
  3. 因服务重启而失去执行线程、永远停在「生成中」的任务记录。
  4. *
* 用 Spring 自带的 {@code @Scheduled} 而非 Quartz JobHandler:后者需要在管理后台手工登记任务, * 漏登记就会静默不执行,而这里的清理属于「不执行就会占满磁盘」的兜底逻辑,必须开箱即跑。 */ @Slf4j @Component @RequiredArgsConstructor public class MesProQrExportCleanupTask { private final MesProQrExportTaskService taskService; /** * 每 5 分钟清理一次:与默认 10 分钟的临时文件保留期匹配,避免残留文件长时间占用磁盘 */ @Scheduled(cron = "0 */5 * * * ?") public void cleanup() { try { int files = taskService.cleanupExpiredFiles(); int tasks = taskService.recycleStaleTasks(); if (files > 0 || tasks > 0) { log.info("[cleanup][二维码导出清理完成:删除临时文件 {} 个,回收残留任务 {} 个]", files, tasks); } } catch (Exception e) { log.error("[cleanup][二维码导出清理失败]", e); } } /** * 启动时立刻回收一次残留任务 *

* 进程重启后运行态注册表为空,此时表中的非终态记录必定没有执行线程在推进, * 立刻回收可避免它们以「生成中」的状态一直挂在界面上(否则要等到下一次定时清理)。 */ @EventListener(ApplicationReadyEvent.class) public void recycleOnStartup() { try { int tasks = taskService.recycleStaleTasks(); if (tasks > 0) { log.info("[recycleOnStartup][启动回收残留二维码导出任务 {} 个]", tasks); } } catch (Exception e) { log.error("[recycleOnStartup][启动回收二维码导出任务失败]", e); } } }