[英]Graceful shutdown with spring and long-running threads
我们遇到的问题是有多个异步线程处理一堆数据并且需要几分钟甚至几个小时才能结束。 Pod 还处理其他一些短期运行的请求。
可能需要移动 pod,并且在此处理过程中会发生关闭。 在这种情况下,我们希望线程在短期内完成工作并留下一个状态,我们可以用它来处理剩余的数据。
我们已经使用了graceful.shutdown=enable
。
现在的想法是,我们在创建异步线程的 bean 中引入一个带有@PreDestroy
的方法。 调用此方法时,它将在不同的 bean 中设置一个“关闭”标志。 所有长时间运行的线程在处理过程中都会检查此标志,当它为真时将停止处理,并将其处理的干净 state 写入数据库。
这或多或少是有效的……但并非总是如此。
正如我首先获得关闭触发器后所了解的那样,有一个可配置的时间spring.lifecycle.timeout-per-shutdown-phase
线程可以在不减少任何所需资源的情况下继续处理它们的工作。 时间结束后,所有的 shutdownhooks 都以未知的顺序被处理。 这让我想到,当我使用带有@preDestroy
和标志的方法时,我可能没有留下干净的 state 的所有必要资源。
有更好的解决方案吗?
是否需要向线程添加更多配置,如setAwaitTerminationSeconds(60);
或setWaitForTasksToCompleteOnShutdown(true);
?
我发现,在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
}
你需要确保你的run()
方法没有做任何事情,当preDestroy()
已经被调用时,因此是shutdown
- 标志。
synchronize
的作用是, preDestroy()
会自动等待,直到run()
定期完成。 只有这样preDestroy()
才会被调用,并且通过设置shutDown
标志,它可以防止它启动另一个长时间运行的线程,即使再次调用run()
也是如此。 相反run()
立即返回。
因为否则,如果您不同步,则在 spring 之后会立即调用preDestroy()
- 服务器收到shutdown
信号,但 spring thinks
如果preDestroy()
已运行并成功完成,它可以立即自行关闭。 这不是您想要的,因为所有run()
线程都会被中断。
我还发现,上面的这个例子在使用@Scheduled
- 注释时不起作用(而不是在构造函数中调用taskScheduler.scheduleWithFixedDelay(this, 100)
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.