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

Apache Camel PollEnrich cacheSize(-1)多次重投递场景下无法重复消费ACK文件问题咨询

解决Apache Camel pollEnrich多次重投无法重复消费同一ACK文件的问题

你碰到的这个问题,核心原因是Apache Camel SFTP组件默认启用了幂等性机制——它会自动记录已经消费过的文件,哪怕你给pollEnrich加了cacheSize(-1)关闭了聚合器的内部缓存,SFTP端点本身还是会跳过那些已经标记为“已消费”的文件,导致第二次及以后的重投无法再获取同一个ACK文件。

下面给你几个可行的解决方案,按推荐优先级排序:

方案1:关闭ACK SFTP端点的幂等性

这是最简单直接的方案,只需要在你的sftpAckEndpoint的URI中添加idempotent=false参数,彻底关闭SFTP组件的文件消费跟踪。

比如你的原ACK端点URI是:

sftp://username@your-sftp-host/ack-folder?fileName=ack-${header.fileName}.txt

修改后:

sftp://username@your-sftp-host/ack-folder?fileName=ack-${header.fileName}.txt&idempotent=false

这样每次pollEnrich执行时,都会重新检查并拉取这个固定名称的ACK文件,完全不受之前消费记录的影响。

方案2:自定义幂等仓库(兼顾幂等与重投需求)

如果你不想完全关闭幂等性(比如担心重复处理其他正常文件),可以自定义一个幂等仓库,让它在路由重投时允许重复消费目标ACK文件:

  1. 实现IdempotentRepository接口,重写contains方法:

    public class RetryAwareIdempotentRepository implements IdempotentRepository<String> {
        private final IdempotentRepository<String> delegate = MemoryIdempotentRepository.memoryIdempotentRepository();
    
        @Override
        public boolean contains(String key) {
            Exchange exchange = ExchangeHelper.getCurrentExchange();
            // 如果当前是重投请求,直接返回false,允许重复消费
            if (exchange != null && exchange.isRedelivered()) {
                return false;
            }
            return delegate.contains(key);
        }
    
        // 其他方法直接委托给delegate实现
        @Override
        public boolean add(String key) { return delegate.add(key); }
        @Override
        public boolean remove(String key) { return delegate.remove(key); }
        @Override
        public void clear() { delegate.clear(); }
        @Override
        public boolean confirm(String key) { return delegate.confirm(key); }
    }
    
  2. 将这个自定义仓库配置到SFTP端点:

    // 初始化自定义幂等仓库
    IdempotentRepository<String> retryRepo = new RetryAwareIdempotentRepository();
    // 在构建sftpAckEndpoint时指定仓库
    String sftpAckEndpoint = "sftp://username@your-sftp-host/ack-folder?fileName=ack-${header.fileName}.txt&idempotentRepository=#retryRepo";
    // 将仓库注册到Camel上下文
    camelContext.getRegistry().bind("retryRepo", retryRepo);
    

这个方案既保留了正常场景下的幂等性,又能在路由重投时绕过消费记录,重复获取ACK文件。

方案3:使用noop=true参数(适合只读场景)

如果你的ACK文件只会被读取而不会被修改、移动或删除,可以在SFTP端点添加noop=true参数。这个参数会让组件以只读模式处理文件,同时默认关闭幂等性,每次都会重新读取文件内容。

示例URI:

sftp://username@your-sftp-host/ack-folder?fileName=ack-${header.fileName}.txt&noop=true

⚠️ 注意:noop=true会让SFTP组件完全不修改文件状态,如果你后续有需要移动/删除ACK文件的需求,这个方案就不适用了。


内容的提问来源于stack exchange,提问作者Midovsky

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 23:32:46