正常关闭Spring集成流程

时间:2018-11-15 15:25:36

标签: spring-integration

我有一个spring集成应用程序,我想正常关闭它。 该应用程序在docker容器中运行,我要关闭的流程将相当数量的XML文件从一个外部系统传输到另一个外部系统。

要求是:如果应用程序必须关闭,则当前文件传输应完成,并且之后不应该再触摸任何文件。

到目前为止我学到的东西和做过的事情:   -docker stop将SIGTERM发送到容器主进程,然后在10秒后发送SIGKILL(可通过--time = x选项配置)   -我实现了一个ApplicationListener并将其注册为@Bean,因此它将在应用程序上下文中注册。   -Flow使用带有transactionManager的轮询器,因此ApplicationListener可以确定轮询器是否有未完成的事务,如果是,则Listener会等待一段时间。

我的问题现在是: 使用此解决方案,我可以等到当前文件传输完成后,但无法告诉流程停止读取入站文件。如果传输完成,并且在ApplicationListener等待时又有另一个文件到达,则Flow将抓取该文件并开始另一个传输,这可能会在SIGKILL到达时放弃。 将流作为生命周期注入和对stop()的调用似乎不像我想的那样。

我的问题是,有没有办法告诉Flow,他应该完成工作但不应该听任何到达的消息?

到目前为止,这是我的代码: 出站流量:

  @Bean
  public PseudoTransactionManager transactionManager() {
    return new PseudoTransactionManager();
  }

  @Bean
  public TransactionSynchronizationFactory transactionSynchronizationFactory() {
    final ExpressionEvaluatingTransactionSynchronizationProcessor processor = new ExpressionEvaluatingTransactionSynchronizationProcessor();
    processor.setBeanFactory(beanFactory);
    return new DefaultTransactionSynchronizationFactory(processor);
  }


  @Bean
  public PollerSpec orderOutboundFlowTempFileInPoller() {
    return Pollers
        .fixedDelay(pollerDelay)
        .maxMessagesPerPoll(100)
        .transactional(transactionManager())
        .transactionSynchronizationFactory(transactionSynchronizationFactory());
  }

  @Bean
  public IntegrationFlow orderOutboundFlowTempFileIn() {
    return IntegrationFlows
        .from(Files.inboundAdapter(new File(temporaryPath + '/' + OrderUtils.SUBDIR_TMP_ORDER))
                .filterFunction(
                    f -> OrderUtils.fileInputFilter(f, partnerConfigRepo, "orderOutboundFlowTempFileIn")),
            e -> e.poller(orderOutboundFlowTempFileInPoller())) ...

应用程序:

  public static void main(final String[] args) throws Exception {
    SpringApplication.run(App.class, args);
  }

  @Bean
  public GracefulShutdown gracefulShutdown() {
    return new GracefulShutdown();
  }

  private static class GracefulShutdown implements ApplicationListener<ContextClosedEvent> {
    private static final Logger LOG = LoggerFactory.getLogger(GracefulShutdown.class);

    @Autowired
    private Lifecycle orderOutboundFlowTempFileIn;

    @Override public void onApplicationEvent(ContextClosedEvent event) {
      LOG.info("Trying to gracefully shutdown App");
      ApplicationContext context = event.getApplicationContext();
      PollerSpec outboundFlowTempFileInPoller = context.getBean(PollerSpec.class, "orderOutboundFlowTempFileInPoller");

      orderOutboundFlowTempFileIn.stop();
      TransactionInterceptor transactionManager = (TransactionInterceptor) (outboundFlowTempFileInPoller.get()
          .getAdviceChain()
          .iterator().next());
      if (transactionManager.getTransactionManager() instanceof AbstractPlatformTransactionManager) {
        final TransactionStatus transaction = transactionManager.getTransactionManager().getTransaction(null);
        LOG.info("This is the transaction: " + transaction.toString() + ", isActive? " + !transaction.isCompleted());
        while (!transaction.isCompleted()) {
          try {
            LOG.info("Still active, waiting 30 more seconds");
            Thread.sleep(30000);
          } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
          }
        }
        LOG.info("Transaction completed");
      }
    }
  }

1 个答案:

答案 0 :(得分:1)

实际上,您只需要停止SourcePollingChannelAdapter的{​​{1}}。为此,您需要向Files.inboundAdapter() lambda中添加.id()。 并在需要停止它时使用该ID来检索e

这样,您就停止了立即接收新文件的操作,而那些正在运行中的文件也将正确完成。

由于所有下游组件都是被动的,因此没有理由从此处停止整个流程。