我有一个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");
}
}
}
答案 0 :(得分:1)
实际上,您只需要停止SourcePollingChannelAdapter
的{{1}}。为此,您需要向Files.inboundAdapter()
lambda中添加.id()
。
并在需要停止它时使用该ID来检索e
。
这样,您就停止了立即接收新文件的操作,而那些正在运行中的文件也将正确完成。
由于所有下游组件都是被动的,因此没有理由从此处停止整个流程。