SpringBoot+Apache Camel SFTP路由重投递失效问题求助
解决Apache Camel SFTP连接异常重投递失效问题
问题根源
你的问题核心在于:SFTP消费者在**poll阶段(执行ls列文件操作)**抛出的异常,是由Camel的PollingConsumerPollStrategy处理的,而非路由中配置的onException重投递机制。默认的RemoteFilePollingConsumerPollStrategy在处理异常时,rollback方法会返回false,这会告诉调度器直接放弃本次poll的重试,直接进入异常处理器,导致你配置的maximumRedeliveries完全不生效。
解决方案
要实现poll阶段的重试,需要自定义PollStrategy,针对特定的临时异常返回true,让调度器重新执行poll操作;同时调整onException配置,确保重试耗尽后再触发自定义错误处理。
1. 自定义SFTP重试PollStrategy
import org.apache.camel.Exchange; import org.apache.camel.component.file.remote.RemoteFilePollingConsumerPollStrategy; import java.io.IOException; public class SftpRetryPollStrategy extends RemoteFilePollingConsumerPollStrategy { private int maxRetries = 3; private int retryCount = 0; @Override public boolean rollback(Exchange exchange, Throwable cause) throws Exception { // 拆解异常链,定位底层IOException Throwable rootCause = getRootCause(cause); if (rootCause instanceof IOException && "input stream closed".equals(rootCause.getMessage())) { if (retryCount < maxRetries) { retryCount++; // 返回true,通知调度器重试本次poll return true; } else { // 重试耗尽,重置计数后返回false,触发后续异常处理 retryCount = 0; return false; } } // 其他异常沿用默认处理逻辑 return super.rollback(exchange, cause); } @Override public void commit(Exchange exchange) throws Exception { // poll成功后重置重试计数 retryCount = 0; super.commit(exchange); } private Throwable getRootCause(Throwable cause) { while (cause.getCause() != null) { cause = cause.getCause(); } return cause; } // 配置重试次数的setter public void setMaxRetries(int maxRetries) { this.maxRetries = maxRetries; } }
2. 注册自定义PollStrategy到Spring容器
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class CamelConfig { @Bean public SftpRetryPollStrategy sftpRetryPollStrategy() { SftpRetryPollStrategy strategy = new SftpRetryPollStrategy(); strategy.setMaxRetries(3); // 设置目标重试次数 return strategy; } }
3. 修改SFTP端点配置,绑定自定义PollStrategy
在路由的SFTP端点中添加pollStrategy参数,指向自定义的bean实例:
@Override public void configure() { onException(IOException.class) .logHandled(true) .log("SFTP重试耗尽,触发IOException处理") .bean(consumerExceptionHandler, "handleIOException") .handled(true) .end(); onException(Exception.class) .logHandled(true) .bean(consumerExceptionHandler, "handleException") .handled(true) .end(); from("sftp://user@host:22/directory?password=secret&disconnect=true&pollStrategy=#sftpRetryPollStrategy") .routeId("sftpRouteWithRetry") .log("Starting SFTP route to fetch files") .to(myQueue) .log("File downloaded successfully to /local/directory") .end(); }
4. 调整重试间隔(可选)
如果需要控制两次poll重试的间隔,可以通过SFTP端点的delay参数调整基础调度间隔;若需要在重试时动态延长间隔,可在自定义PollStrategy的rollback方法中添加Thread.sleep()逻辑。
关键说明
- poll阶段与路由阶段的区别:Camel的
onException重投递针对的是路由处理阶段的异常(比如to(myQueue)抛出的异常),而SFTP的ls操作属于消费者poll阶段的异常,由PollStrategy独立控制。 - 自定义PollStrategy的核心逻辑:通过
rollback方法返回true,告诉调度器重新执行poll操作,直到重试耗尽后返回false,触发onException的自定义错误处理逻辑。
内容的提问来源于stack exchange,提问作者besek
相关产品推荐
相关产品推荐

