简体   繁体   English

使用 spring 和长时间运行的线程正常关闭

[英]Graceful shutdown with spring and long-running threads

We have the problem that there are multiple async threads that process a bunch of data and need minutes or some of them even hours to end.我们遇到的问题是有多个异步线程处理一堆数据并且需要几分钟甚至几个小时才能结束。 The pod also processes some other short running request. Pod 还处理其他一些短期运行的请求。

It might occur that the pod has to be moved, and a shutdown will happen during this processing.可能需要移动 pod,并且在此处理过程中会发生关闭。 In this case, we want the threads to finish their work in short term and leave a status, which we can use to process the remaining data.在这种情况下,我们希望线程在短期内完成工作并留下一个状态,我们可以用它来处理剩余的数据。

We already use graceful.shutdown=enable .我们已经使用了graceful.shutdown=enable

The idea now is that we introduce a method with @PreDestroy in the bean that creates the async threads.现在的想法是,我们在创建异步线程的 bean 中引入一个带有@PreDestroy的方法。 When this method is called, it will set a "shutdown" flag in a different bean.调用此方法时,它将在不同的 bean 中设置一个“关闭”标志。 All the long-running threads check this flag during processing and will stop processing when it's true and write a clean state of their processing to the database.所有长时间运行的线程在处理过程中都会检查此标志,当它为真时将停止处理,并将其处理的干净 state 写入数据库。

This is more or less working... but not all the time.这或多或少是有效的……但并非总是如此。

As I understood after getting the shutdown trigger at first, there is a configurable time spring.lifecycle.timeout-per-shutdown-phase where threads can continue processing their work without reduction in any of the needed resources.正如我首先获得关闭触发器后所了解的那样,有一个可配置的时间spring.lifecycle.timeout-per-shutdown-phase线程可以在不减少任何所需资源的情况下继续处理它们的工作。 After the time is over, all the shutdownhooks are processed in an unknown order.时间结束后,所有的 shutdownhooks 都以未知的顺序被处理。 This brings me to the thought that I might not have all the necessary resources for leaving a clean state, when I use the approach with the @preDestroy and the flag.这让我想到,当我使用带有@preDestroy和标志的方法时,我可能没有留下干净的 state 的所有必要资源。

Is there a better solution to this?有更好的解决方案吗?

Is there a need to add some more configuration to the threads like setAwaitTerminationSeconds(60);是否需要向线程添加更多配置,如setAwaitTerminationSeconds(60); or setWaitForTasksToCompleteOnShutdown(true);setWaitForTasksToCompleteOnShutdown(true); ?

What I found is, when using graceful.shutdown=enable and @PreDestroy in spring, that you need to synchronize the run() method and the @PreDestroy method (provided that both are in the same class):我发现,在spring中使用graceful.shutdown=enable@PreDestroy时,需要synchronize run()方法和@PreDestroy方法(前提是两者在同一个类中):

@Service
public class MyClass implements Runnable {
  private volatile boolean shutDown = false;
  public MyClass( TaskScheduler taskScheduler) {
        taskScheduler.scheduleWithFixedDelay(this, 100);
  }
  @PreDestroy
    public synchronized void preDestroy() {
        this.shutDown = true;
        log.info("@PreDestroy Callback triggered for shutting down");
    }
 @Override
    public synchronized void run() {
        if (this.shutDown) {
            this.shutdownCounter++;
            return;
        }
        // put in here, whatever you long running task needs to do
    }

And you need to make sure, that your run() method is not doing anything, when preDestroy() was already called, hence the shutdown - flag.你需要确保你的run()方法没有做任何事情,当preDestroy()已经被调用时,因此是shutdown - 标志。

What the synchronize does is, that preDestroy() automatically waits until run() is finished regularly. synchronize的作用是, preDestroy()会自动等待,直到run()定期完成。 Only then preDestroy() is called, and by setting the shutDown flag, it prevents that it starts another long running thread, even in case run() is called again.只有这样preDestroy()才会被调用,并且通过设置shutDown标志,它可以防止它启动另一个长时间运行的线程,即使再次调用run()也是如此。 Instead run() returns immediately.相反run()立即返回。

Because otherwise, when you don't synchronized, then the preDestroy() is called immediately after the spring - server get a shutdown signal but spring thinks if preDestroy() has run and finished successful, that it can shut down itself immediately.因为否则,如果您不同步,则在 spring 之后会立即调用preDestroy() - 服务器收到shutdown信号,但 spring thinks如果preDestroy()已运行并成功完成,它可以立即自行关闭。 Which is not what you want, because then all run() threads gets interrupted.这不是您想要的,因为所有run()线程都会被中断。

I also found, that this example above does not work when using the @Scheduled - annotation (instead of calling taskScheduler.scheduleWithFixedDelay(this, 100) in the constructor)我还发现,上面的这个例子在使用@Scheduled - 注释时不起作用(而不是在构造函数中调用taskScheduler.scheduleWithFixedDelay(this, 100)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM