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文件:
实现
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); } }将这个自定义仓库配置到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
相关产品推荐
相关产品推荐

