Skip to content

SftpSession.write() is not thread-safe #9796

Closed
@artembilan

Description

@artembilan

Discussed in #9793

Originally posted by vnxvd January 27, 2025
Hello everybody,
I am getting following error message while using Spring Integration Sftp.

WritePendingException: A write operation is already pending; cannot write 6905 bytes, stackTrace: 
org.apache.sshd.common.io.WritePendingException: A write operation is already pending; cannot write 6905 bytes 
at org.apache.sshd.common.channel.ChannelAsyncOutputStream.writeBuffer(ChannelAsyncOutputStream.java:110) 
at org.apache.sshd.sftp.client.impl.DefaultSftpClient.write(DefaultSftpClient.java:308) 
at org.apache.sshd.sftp.client.impl.SftpOutputStreamAsync.internalFlush(SftpOutputStreamAsync.java:360) 
at org.apache.sshd.sftp.client.impl.SftpOutputStreamAsync.flush(SftpOutputStreamAsync.java:293) 
at org.springframework.util.FileCopyUtils.copy(FileCopyUtils.java:112) 
at org.springframework.integration.sftp.session.SftpSession.write(SftpSession.java:140)

This is the code for creating Sftp Session Factory.

DefaultSftpSessionFactory sessionFactory = new DefaultSftpSessionFactory(true);
        sessionFactory.setHost(connection.getHost());
        if (connection.getPort() != null) {
            sessionFactory.setPort(connection.getPort());
        }
        sessionFactory.setUser(connection.getUser());
        if (StringUtils.isNotBlank(connection.getPassword())) {
            sessionFactory.setPassword(connection.getPassword());
        } else if (StringUtils.isNotBlank(connection.getPrivateKey())) {
            sessionFactory.setPrivateKey(new FileSystemResource(connection.getPrivateKey()));
            if (StringUtils.isNotBlank(connection.getPrivateKeyPassphrase())) {
                sessionFactory.setPrivateKeyPassphrase(connection.getPrivateKeyPassphrase());
            }
        }
        sessionFactory.setAllowUnknownKeys(true);
        return sessionFactory;

This is the code for creating Sftp Session and use the session.

SftpSession sftpSession = sessionFactory.getSession();
        if (!sftpSession.exists(targetFile)) {
            try (InputStream is = new FileInputStream(sourceFile)) {
                sftpSession.write(is, targetFile);
            } catch (IOException e) {// handle exception here}
        }

Library versions:
Spring Boot 3.4.0
Spring Integration Sftp 6.4.0
Apache sshd Sftp 2.14.0
As a temporary solution, I am using "synchronized" keyword on the method which using the SftpSession object to fix the error. Please let me know if you have a better idea to fix this error message.
Thanks.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions