Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring integration Spring集成-处理过时的sftp会话_Spring Integration_Jsch_Spring Integration Sftp - Fatal编程技术网

Spring integration Spring集成-处理过时的sftp会话

Spring integration Spring集成-处理过时的sftp会话,spring-integration,jsch,spring-integration-sftp,Spring Integration,Jsch,Spring Integration Sftp,我已经实现了以下场景: 以字节[]形式保存消息的队列通道 MessageHandler,轮询队列通道并通过sftp上载文件 一个转换器,侦听errorChannel并将从失败消息中提取的有效负载发送回queueChannel(被认为是处理失败消息的错误处理程序,因此不会丢失任何内容) 如果sftp服务器在线,则一切正常 如果sftp服务器关闭,则作为转换器到达的错误消息为: org.springframework.messaging.MessagingException: Failed to o

我已经实现了以下场景:

  • 以字节[]形式保存消息的队列通道
  • MessageHandler,轮询队列通道并通过sftp上载文件
  • 一个转换器,侦听errorChannel并将从失败消息中提取的有效负载发送回queueChannel(被认为是处理失败消息的错误处理程序,因此不会丢失任何内容)
  • 如果sftp服务器在线,则一切正常

    如果sftp服务器关闭,则作为转换器到达的错误消息为:

    org.springframework.messaging.MessagingException: Failed to obtain pooled item; nested exception is java.lang.IllegalStateException: failed to create SFTP Session
    
    转换器无法对此执行任何操作,因为有效负载的failedMessage为null,并且本身会引发异常。变压器释放了信息

    我如何配置我的流,使转换器获得正确的消息,以及未成功上载文件的相应负载

    我的配置:

      @Bean
      public MessageChannel toSftpChannel() {
        final QueueChannel channel = new QueueChannel();
        channel.setLoggingEnabled(true);
        return new QueueChannel();
      }
    
      @Bean
      public MessageChannel toSplitter() {
        return new PublishSubscribeChannel();
      }
    
      @Bean
      @ServiceActivator(inputChannel = "toSftpChannel", poller = @Poller(fixedDelay = "10000", maxMessagesPerPoll = "1"))
      public MessageHandler handler() {
        final SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
        handler.setRemoteDirectoryExpression(new LiteralExpression(sftpRemoteDirectory));
        handler.setFileNameGenerator(message -> {
          if (message.getPayload() instanceof byte[]) {
            return (String) message.getHeaders().get("name");
          } else {
            throw new IllegalArgumentException("byte[] expected in Payload!");
          }
        });
        return handler;
      }
    
      @Bean
      public SessionFactory<LsEntry> sftpSessionFactory() {
        final DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
    
        final Properties jschProps = new Properties();
        jschProps.put("StrictHostKeyChecking", "no");
        jschProps.put("PreferredAuthentications", "publickey,password");
        factory.setSessionConfig(jschProps);
    
        factory.setHost(sftpHost);
        factory.setPort(sftpPort);
        factory.setUser(sftpUser);
        if (sftpPrivateKey != null) {
          factory.setPrivateKey(sftpPrivateKey);
          factory.setPrivateKeyPassphrase(sftpPrivateKeyPassphrase);
        } else {
          factory.setPassword(sftpPasword);
        }
        factory.setAllowUnknownKeys(true);
        return new CachingSessionFactory<>(factory);
      }
    
      @Bean
      @Splitter(inputChannel = "toSplitter")
      public DmsDocumentMessageSplitter splitter() {
        final DmsDocumentMessageSplitter splitter = new DmsDocumentMessageSplitter();
        splitter.setOutputChannelName("toSftpChannel");
        return splitter;
      }
    
      @Transformer(inputChannel = "errorChannel", outputChannel = "toSftpChannel")
      public Message<?> errorChannelHandler(ErrorMessage errorMessage) throws RuntimeException {
    
        Message<?> failedMessage = ((MessagingException) errorMessage.getPayload())
          .getFailedMessage();
        return MessageBuilder.withPayload(failedMessage)
                             .copyHeadersIfAbsent(failedMessage.getHeaders())
                             .build();
      }
    
      @MessagingGateway 
      public interface UploadGateway {
    
        @Gateway(requestChannel = "toSplitter")
        void upload(@Payload List<byte[]> payload, @Header("header") DmsDocumentUploadRequestHeader header);
      }
    

    null
    failedMessage
    是一个bug;复制

    我不建议在这种情况下使用
    QueueChannel
    。如果使用直接通道,则可以将配置为尝试重新交付。当重试次数用尽时(如果这样配置),异常将被抛出回调用线程

    将建议添加到
    SftpMessageHandler
    adviceChain
    属性中

    编辑

    通过在可轮询通道和sftp适配器之间插入桥接器,可以解决“丢失”的failedMessage问题:

    @Bean
    @ServiceActivator(inputChannel = "toSftpChannel", poller = @Poller(fixedDelay = "5000", maxMessagesPerPoll = "1"))
    public BridgeHandler bridge() {
        BridgeHandler bridgeHandler = new BridgeHandler();
        bridgeHandler.setOutputChannelName("toRealSftpChannel");
        return bridgeHandler;
    }
    
    @Bean
    @ServiceActivator(inputChannel = "toRealSftpChannel")
    public MessageHandler handler() {
        final SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
        handler.setRemoteDirectoryExpression(new LiteralExpression("foo"));
        handler.setFileNameGenerator(message -> {
            if (message.getPayload() instanceof byte[]) {
                return (String) message.getHeaders().get("name");
            }
            else {
                throw new IllegalArgumentException("byte[] expected in Payload!");
            }
        });
        return handler;
    }
    

    抱歉,我以为您正在轮询入站通道适配器。打开调试日志并遵循消息流。如果您仍然无法理解,请将日志发布到某个地方。如果您担心邮件丢失,您可能也不应该使用
    QueueChannel
    。@gary您好gary,谢谢您的回复。。。我最担心的是上传失败会导致文件丢失。。据我所知,我必须以某种方式将文件排成队列,以便能够重试上载。。。或者有更好的方法来处理这样的用例吗?这是日志,请查看我的答案。您可以使用
    QueueChannel
    ,只要您还使用事务性
    ChannelMessageStore
    ,例如
    JdbcChannelMessageStore
    。在这种情况下,当重试结束后引发异常时,事务将回滚,消息将保留在存储中。@ArtemBilan:请提供一些示例,如何使用RedisChannelPriorityMessageStore和Java注释设置QueueChannel?@RokPurkeljc有一个带有mongo存储的Java配置示例。另请参见我的编辑,了解
    null
    failedMessage
    的解决方法。Redis不是事务性的,因此,不能保证在例外情况下不会丢失消息,除非使用Oracle数据源设置JdbcChannelMessageStore。如何在自定义(使用PollerMetadata)定义的带有Java注释的轮询器上启用@Transactional(请参阅更新)?
    @Bean
    @ServiceActivator(inputChannel = "toSftpChannel", poller = @Poller(fixedDelay = "5000", maxMessagesPerPoll = "1"))
    public BridgeHandler bridge() {
        BridgeHandler bridgeHandler = new BridgeHandler();
        bridgeHandler.setOutputChannelName("toRealSftpChannel");
        return bridgeHandler;
    }
    
    @Bean
    @ServiceActivator(inputChannel = "toRealSftpChannel")
    public MessageHandler handler() {
        final SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
        handler.setRemoteDirectoryExpression(new LiteralExpression("foo"));
        handler.setFileNameGenerator(message -> {
            if (message.getPayload() instanceof byte[]) {
                return (String) message.getHeaders().get("name");
            }
            else {
                throw new IllegalArgumentException("byte[] expected in Payload!");
            }
        });
        return handler;
    }