Quarkus Camel路由:如何触发文件移至失败目录?
基于Quarkus的Camel多行CSV文件处理:出错后移至失败目录
我们用基于Quarkus的Camel路由处理多行CSV文件,from端点已配置moveFailed参数。当前实现支持单行处理出错时不中断流程,但需要补充逻辑:只要文件处理过程中出现过错误,最终就把整个文件移到失败目录。现有代码示例如下:
from("file:/C:/dev/_import?moveFailed=failed&delete=true&readLock=changed") .onException(Throwable.class) .setHeader("fileFailedPartly").simple("true") .log(LoggingLevel.ERROR, "${exception.stacktrace}") .log(LoggingLevel.ERROR, "Exception occurred when reading row - continue with file ${header.CamelFileName}") .continued(true) .end() .bean(CsvParser.class) .split().body() .log(LoggingLevel.INFO, "Sending row ${header.CamelSplitIndex}++ of ${header.CamelSplitSize}") .delay(1000) .bean("sender","send") .end() .choice() .when(simple("${header.fileFailedPartly} == true")) .log(LoggingLevel.INFO, "File ${header.CamelFileName} partly failed. Move to failed.") //trigger move to failed .end();
实现方案
因为我们用了continued(true)让路由在单行出错时继续执行,Camel默认的moveFailed机制不会触发(它只在路由整体抛出未捕获异常时生效),所以需要手动实现文件移动逻辑:
- 移除
delete=true:from端点不要配置delete=true,避免文件被提前删除,改为后续手动控制文件的删除或移动。 - 保存原始文件名:在split操作前把原始文件名存到自定义Header里,防止split后Header丢失或被覆盖。
- 手动移动并处理文件:在choice分支中,根据
fileFailedPartly标记,分别处理失败和成功的情况。
修改后的完整代码:
from("file:/C:/dev/_import?moveFailed=failed&readLock=changed") .onException(Throwable.class) .setHeader("fileFailedPartly", simple("true")) .log(LoggingLevel.ERROR, "${exception.stacktrace}") .log(LoggingLevel.ERROR, "读取行时发生异常 - 继续处理文件 ${header.CamelFileName}") .continued(true) .end() // 提前保存原始文件名,避免split后丢失 .setHeader("OriginalFileName", simple("${header.CamelFileName}")) .bean(CsvParser.class) .split().body() .log(LoggingLevel.INFO, "正在发送第 ${header.CamelSplitIndex} 行,共 ${header.CamelSplitSize} 行") .delay(1000) .bean("sender", "send") .end() .choice() .when(simple("${header.fileFailedPartly} == true")) .log(LoggingLevel.INFO, "文件 ${header.OriginalFileName} 部分行处理失败,移至失败目录") // 手动移动文件到失败目录 .to("file:/C:/dev/_import/failed?fileName=${header.OriginalFileName}") // 删除原文件 .to("file:/C:/dev/_import?delete=true&fileName=${header.OriginalFileName}") .otherwise() .log(LoggingLevel.INFO, "文件 ${header.OriginalFileName} 全部处理完成,删除原文件") // 处理成功则删除原文件 .to("file:/C:/dev/_import?delete=true&fileName=${header.OriginalFileName}") .end();
关键说明
- 手动移动文件时,直接用
file组件指定失败目录和文件名,确保文件被正确转移。 - 自定义
OriginalFileNameHeader是因为split操作会生成子Exchange,可能导致原始的CamelFileNameHeader不可用,提前保存能避免这个问题。 - 如果需要更简洁的实现,也可以用
onCompletion钩子来统一处理,但上述方式逻辑更直观,便于调试和维护。
内容的提问来源于stack exchange,提问作者AnnetteC
相关产品推荐
相关产品推荐

