Redis-5-doFormatAsync()方法

FormatService.doFormatAsync()

异步执行排版任务,处理排版全流程:该方法被标记为 @Async("notificationExecutor"),表示它会在单独的线程中异步执行,避免阻塞主线程;包括文件下载、排版处理、文件上传、状态更新等完整流程。
业务流程:初始化与前置校验 -- 文件保存到临时目录 -- 调用外部排版服务 -- 清理"排版中"状态 -- 上传排版结果 -- 保存结果到 Redis -- 更新数据库状态

java 复制代码
@Async("notificationExecutor")
public void doFormatAsync(Integer styleId, Integer formId, String sourceNodeId, String fileId, String fileName, Long userId, String taskKey) {
   // 临时文件路径,用于最后清理
   String tempFilePath = null;

   try {
       // 1. 初始化与前置校验: 校验原文件是否存在且未被删除。若校验失败,则保存失败状态并清理任务状态。
       KbNode sourceNode = kbNodeMapper.selectById(sourceNodeId);
       if (sourceNode == null || sourceNode.getDeleted() == 1) {
           log.error("FormatService##doFormatAsync-0,排版任务失败,原文件节点不存在,sourceNodeId={}", sourceNodeId);
           saveFailedResultItem(sourceNodeId, fileName, userId);
           stringRedisTemplate.delete(taskKey);
           return;
       }
       // 如果原文件有父节点则使用父节点,否则说明在根目录,使用原文件所属的根节点(通过查询获取)
       String folderNodeId = StringUtils.hasText(sourceNode.getParentId()) ? sourceNode.getParentId(): sourceNodeId;  // 根目录下的文件,暂时使用原nodeId,实际部署时可能需要调整
       FileBean fileBean = fileBeanService.getById(fileId);// 从file表(db2)查询文件信息
       if (fileBean == null || !StringUtils.hasText(fileBean.getFileUrl())) {
           log.info("FormatService##doFormatAsync-1,排版任务失败,文件不存在,fileId={}", fileId);
           // 保存失败状态的结果项
           saveFailedResultItem(sourceNodeId, fileName, userId);
           stringRedisTemplate.delete(taskKey);
           return;
       }

       // 2. 文件下载与临时存储:将原始文件从存储系统下载到本地临时目录。
       // 使用 saveFileToTemp 方法构建临时路径并复制文件。若下载失败,则记录失败状态并退出.
       tempFilePath = saveFileToTemp(fileBean.getFileUrl(), fileName);
       if (tempFilePath == null) {
           log.error("FormatService##doFormatAsync-2,排版任务失败,文件保存到临时目录失败,fileUrl={}", fileBean.getFileUrl());
           saveFailedResultItem(sourceNodeId, fileName, userId);
           stringRedisTemplate.delete(taskKey);
           return;
       }

       // 3. 调用外部排版服务:调用公文排版服务生成排版后的文件(PDF 和 Word)。
       // callExternalFormatService中:读取临时文件内容。根据styleId选择模板。调用 govdocFormatterService.format() 执行排版。将排版结果保存到临时目录。
       FormatCallbackResult callbackResult = callExternalFormatService(styleId, tempFilePath);
       if (callbackResult == null || !callbackResult.isSuccess()) {
           log.error("FormatService##doFormatAsync-4,排版任务失败,外部排版接口调用失败,sourceNodeId={}", sourceNodeId);
           saveFailedResultItem(sourceNodeId, fileName, userId);
           stringRedisTemplate.delete(taskKey);
           return;
       }

       // 4. 删除"排版中"状态的临时结果项:清除任务启动时插入的"排版中"状态项,排版完成或失败时调用。
       removeFormattingResultItem(sourceNodeId, userId);

       // 5. 上传排版结果文件:将排版后的文件上传至文件服务器,并生成新的 nodeId,并保存结果。
       // 分别处理PDF和Word文件、调用uploadSingleFile方法上传文件、FormatResultItem对象保存结果信息
       List<FormatResultItem> resultItems = uploadFormattedFiles(callbackResult, sourceNodeId, fileName, userId, folderNodeId);

       // 6. 保存每个结果项到 Redis,将排版结果持久化到 Redis 中,供前端查询。
       // 使用 FORMAT_ITEM_KEY_PREFIX 保存结果项详情。建立用户、原文件与结果文件之间的映射关系.
       for (FormatResultItem item : resultItems) {
           saveResultItem(item, userId, sourceNodeId);
       }

       // 7. 删除任务状态标识并清理临时文件目录(表示任务完成)
       stringRedisTemplate.delete(taskKey);
   // 捕获所有异常(包括Error和Exception),确保任务失败时能正确记录状态并释放资源。
   } catch (Throwable e) {
       log.error("FormatService##doFormatAsync-e,排版任务异常,userId={}, sourceNodeId={}", userId, sourceNodeId, e);
       // 删除"排版中"的临时结果项
       removeFormattingResultItem(sourceNodeId, userId);
       saveFailedResultItem(sourceNodeId, fileName, userId);
       stringRedisTemplate.delete(taskKey);
   } finally {
       // 7. 清理临时文件目录(无论成功或失败都要清理)
       cleanupTempDirectory(tempFilePath);
   }
}
相关推荐
用户8662978480089 小时前
抓包看 KingbaseES 内部协议?官方给了个现成工具
数据库
wefg19 小时前
【Redis】安装与启动
数据库·redis·缓存
大圣编蚕9 小时前
常见的 Redis 面试题(高频整理)
数据库·redis·缓存
派小心.10 小时前
网站统计采样数据的误差核对
大数据·服务器·前端·数据库·人工智能·小程序·数据分析
龙腾AI白云10 小时前
数字孪生、具身智能、世界模型三者交叉
数据库·人工智能·机器学习·flask·pygame
小猿姐10 小时前
KubeBlocks Enterprise v2.3 发布!
redis·kubernetes·aiops
SelectDB技术团队10 小时前
Apache Doris 基于 Lance 的向量检索深度解析
数据库·数据仓库·数据分析·湖仓一体·apache doris·lakehouse·多模湖仓
这个DBA有点耶11 小时前
从INDEX到JOIN_ORDER:MySQL 8.0 Hint语法体系与五类实战场景
数据库·mysql·架构
数字新视界11 小时前
机房动环监控助力智能管理
大数据·服务器·数据库·动环监控系统·动力与环境监控系统
梅菲塔亚11 小时前
博客_Redis入门到实战
数据库·redis·缓存