Gerry Gry
Gerry Gry

Reputation: 182

How to make sure SFTP session always close at the end of the spring-batch

My application is based on spring-boot 2.1.6 equipped with spring-batch (chunks approach) and spring-integration to handle the SFTP.

High level functionality is to fetch data from DB, generate a text file then send it through SFTP and this task run every 30 mins.

This application already running in production for some time, but if I see the logs there are error about ssh_msg_disconnect 11 idle connection. It will keep like that until I restart the app.

Below is my application code :

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);
    }

}

step for sending file to 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());
    }

From the error, I know that seems like I opened too many connection. But I'm not sure how to check if the connection are closed every end of the spring-batch.

Upvotes: 2

Views: 5206

Answers (1)

Gary Russell
Gary Russell

Reputation: 174554

If you don't wrap the session factory in a CachingSessionFactory, the session will be closed after each use.

@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;
}

Upvotes: 5

Related Questions