You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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机制不会触发(它只在路由整体抛出未捕获异常时生效),所以需要手动实现文件移动逻辑:

  1. 移除delete=true:from端点不要配置delete=true,避免文件被提前删除,改为后续手动控制文件的删除或移动。
  2. 保存原始文件名:在split操作前把原始文件名存到自定义Header里,防止split后Header丢失或被覆盖。
  3. 手动移动并处理文件:在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 13:26:18