如何确保 SFTP 会话始终在 spring-batch 结束时关闭
Posted
技术标签:
【中文标题】如何确保 SFTP 会话始终在 spring-batch 结束时关闭【英文标题】:How to make sure SFTP session always close at the end of the spring-batch 【发布时间】:2019-12-17 11:16:28 【问题描述】:我的应用程序基于 spring-boot 2.1.6,配备了 spring-batch(块方法)和 spring-integration 来处理 SFTP。
高级功能是从数据库中获取数据,生成文本文件,然后通过 SFTP 发送,此任务每 30 分钟运行一次。
此应用程序已经在生产环境中运行了一段时间,但如果我看到日志,则会出现关于 ssh_msg_disconnect 11 idle connection 的错误。它会一直保持这种状态,直到我重新启动应用程序。
以下是我的应用程序代码:
SftpConfig.java
@Configuration
public class SftpConfig
@Autowired
ApplicationProperties applicationProperties;
@Bean
public SessionFactory<LsEntry> sftpSessionFactory()
final DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost(applicationProperties.getSftp().getHost());
factory.setUser(applicationProperties.getSftp().getUser());
factory.setPassword(applicationProperties.getSftp().getPass());
factory.setAllowUnknownKeys(true);
return new CachingSessionFactory<>(factory);
@Bean
@ServiceActivator(inputChannel = "toSftpChannel", adviceChain = "retryAdvice")
public MessageHandler handler()
final SftpMessageHandler handler = new SftpMessageHandler(this.sftpSessionFactory());
handler.setRemoteDirectoryExpression(new LiteralExpression(applicationProperties.getSftp().getPath()));
handler.setFileNameGenerator((final Message<?> message) ->
if (message.getPayload() instanceof File)
return ((File) message.getPayload()).getName();
else
throw new IllegalArgumentException("File expected as payload.");
);
return handler;
@Bean
public RequestHandlerRetryAdvice retryAdvice()
final RequestHandlerRetryAdvice advice = new RequestHandlerRetryAdvice();
final RetryTemplate retryTemplate = new RetryTemplate();
final SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(NumberConstants.FIVE);
retryTemplate.setRetryPolicy(retryPolicy);
advice.setRetryTemplate(retryTemplate);
return advice;
@MessagingGateway
public interface UploadGateway
@Gateway(requestChannel = "toSftpChannel")
void upload(File file);
发送文件到 sftp 的步骤
@Autowired
UploadGateway uploadGateway;
private boolean uploadToSharedFolderSuccess(final PaymentStatus paymentStatus, final String strLocalTmpPath)
try
final File fileLocalTmpFullPath = new File(strLocalTmpPath);
uploadGateway.upload(fileLocalTmpFullPath);
catch (final Exception e)
paymentStatus.setStatus(ProcessStatus.ERROR.toString());
paymentStatus.setRemark(StringUtil.appendIfNotEmpty(paymentStatus.getRemark(),
"Error during upload to shared folder - " + e.getMessage()));
return !StringUtils.equalsIgnoreCase(ProcessStatus.ERROR.toString(), paymentStatus.getStatus());
从错误中,我知道似乎我打开了太多连接。但我不确定如何检查连接是否在 spring-batch 的每一端都关闭。
【问题讨论】:
基本上@ServiceActivator 是一个被动组件,它按需从SessionFactory 获取会话。无论如何,下一次通话都应该带来一个新的会话,因为您不使用 isSharedSession 标志。我建议将此标志设置为真。如需参考,请查看属性文档docs.spring.io/spring-integration/docs/5.2.0.M3/reference/html/… 如果您希望会话在使用后物理关闭,请不要使用CachingSessionFactory
。
@Dhiren,isSharedSession 标志在那里,并在初始化会话工厂期间设置为 true .. 关于按需的事情,是否有任何文章可以支持该声明?
@Gary Russell,那我应该用什么?有什么建议吗?
如果你想为每个调用分开会话然后使用 DefaultSessionFactory 否则 CachingSessionFactory。取决于您的用例。
【参考方案1】:
如果您不将会话工厂包装在 CachingSessionFactory
中,则会话将在每次使用后关闭。
@Bean
public DefaultSftpSessionFactory sftpSessionFactory()
final DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost(applicationProperties.getSftp().getHost());
factory.setUser(applicationProperties.getSftp().getUser());
factory.setPassword(applicationProperties.getSftp().getPass());
factory.setAllowUnknownKeys(true);
return factory;
【讨论】:
以上是关于如何确保 SFTP 会话始终在 spring-batch 结束时关闭的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 libssh 和 SFTP 在 C/C++ 中复制文件
php 如何通过连接sftp并下载sftp服务器指定目录下的所有文件到本地?