Spring 集成 FTP InboundChannelAdapter 在网络重置后终止

Spring integration FTP InboundChannelAdapter dies after network reset

我们有一个从 FTP 到 download 文件的用例,并且有一个奇怪的行为,即 ftp 入站适配器在网络重置后停止工作,这是步骤重现问题:

  1. 开始申请
  2. 应用程序开始从ftp服务器下载文件到本地
  3. 定义的本地目录中出现了filename.writing个文件
  4. 拔掉网线(模拟网络重置情况)
  5. 应用程序停止下载文件(显然没有网络连接)
  6. 插上网线。
  7. 下载未重新启动或重置,应用程序保持静止..
  8. 根本没有LOG来识别这个问题。

提前致谢!

更新

这个问题应该通过添加超时来解决defSession.setConnectTimeout(Integer.valueOf(env.getProperty("ftp.timeout.connect")));

AND 下面的代码是在 FTP 阅读客户端上的 工作示例

这是代码片段:

    @Bean
    public DefaultFtpSessionFactory ftpSessionFactory() {
        DefaultFtpSessionFactory defSession = new DefaultFtpSessionFactory();
        defSession.setUsername(env.getProperty("ftp.username"));
        defSession.setPassword(env.getProperty("ftp.password"));
        defSession.setPort(21);
        defSession.setHost(env.getProperty("ftp.host"));

        defSession.setClientMode(FTPClient.PASSIVE_LOCAL_DATA_CONNECTION_MODE);
        defSession.setControlEncoding("UTF-8");

        return defSession;
    }

    @Bean
    PollableChannel ftpChannel() {
        return new QueueChannel(Integer.valueOf(env.getProperty("ftp.channel.size")));
    }

    @Bean
    public FtpInboundFileSynchronizer ftpInboundFileSynchronizer() {
        FtpInboundFileSynchronizer ftpInboundFileSynchronizer = new FtpInboundFileSynchronizer(ftpSessionFactory());
        ftpInboundFileSynchronizer.setDeleteRemoteFiles(Boolean.valueOf(env.getProperty("ftp.directory.delete")));

        FtpRegexPatternFileListFilter ftpRegexPatternFileListFilter = new FtpRegexPatternFileListFilter(pattern);
        ftpInboundFileSynchronizer.setFilter(ftpRegexPatternFileListFilter);
        ftpInboundFileSynchronizer.setRemoteDirectory(env.getProperty("ftp.directory.remote"));

        return ftpInboundFileSynchronizer;
    }

    @Bean
    @InboundChannelAdapter(value = "ftpChannel")
    public FtpInboundFileSynchronizingMessageSource ftpInboundFileSynchronizingMessageSource() {
        FtpInboundFileSynchronizingMessageSource ftpInboundFileSynchronizingMessageSource = new FtpInboundFileSynchronizingMessageSource(ftpInboundFileSynchronizer());
        ftpInboundFileSynchronizingMessageSource.setLoggingEnabled(true);
        ftpInboundFileSynchronizingMessageSource.setCountsEnabled(true);
        ftpInboundFileSynchronizingMessageSource.setAutoCreateLocalDirectory(true);
        ftpInboundFileSynchronizingMessageSource.setLocalDirectory(new File(env.getProperty("ftp.directory.local")));

        return ftpInboundFileSynchronizingMessageSource;
    }

    @Bean(name = PollerMetadata.DEFAULT_POLLER)
    public PollerMetadata defaultPoller() {
        PollerMetadata pollerMetadata = new PollerMetadata();
        pollerMetadata.setErrorHandler(t -> log.error("Failed to retrieve data from FTP: {}", t.getMessage(), t));
        pollerMetadata.setTrigger(new PeriodicTrigger(60, TimeUnit.SECONDS));
        return pollerMetadata;
    }

线程很可能仍挂在读取上 - 如果您从计算机上的实际适配器中拔出电缆,网络堆栈应该通知 java 进程套接字已消失,但如果您从下游路由器拔网线,可能没有信号。 jstack 将显示线程正在做什么。

您需要在会话工厂上设置超时 - 请参阅 the documentation 和 FtpClient java 文档 - dataTimeout 用于读取。