Play Framework + Akka:如何避免执行关闭应用程序时执行的计划任务
Playframework + Akka: how to avoid excuting scheduled tasks executed when shutdown application
我在播放应用程序服务器启动时启动的调度程序有问题,但是一旦应用程序关闭,它就会遇到以下代码部分:
// firstDay something like 1 = monday
private void startScheduler(final ImageService imageService,
final ActorSystem system) {
startImagesCleanupScheduler(imageService, system);
Logger.info("Schedulers started");
}
我的问题是 Runnable
块立即开始执行,而不是仅仅取消任务。
澄清代码:
以下方法启动Scheduler
:
private void startImagesCleanupScheduler(ImageService imageService, ActorSystem system) {
system.scheduler().schedule(
Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay
Duration.create(1, TimeUnit.DAYS), //Frequency 1 days
() -> {
int rows = imageService.cleanupInactiveImages();
Logger.info(String.format("%d inactive unused images cleaned from db", rows));
},
system.dispatcher()
);
}
关机时的日志请注意这里的第一行:
[info] - application - 1 inactive unused images cleaned from db
[info] - application - Shutting down connection pool.
[info] - application - Creating Pool for datasource 'default'
...
[info] - application - Schedulers started
[info] - play.api.Play - Application started (Prod)
你可以看到它执行了调度程序,忽略了它原来的执行时间,然后关闭,然后启动,"Schedulers started" 之后。
什么问题,我如何取消调度程序或防止在关机前播放到 运行?这是 Akka 的错误吗?
我在 OnStartup
内调用 startScheduler
就像下面问题的答案一样:
编辑:
以下是重现问题的最少代码:
首先创建OnStartup
class:
@Singleton
public class OnStartup {
@Inject
public OnStartup(final ActorSystem system) {
startScheduler(system);
}
private void startScheduler(final ActorSystem system) {
startImagesCleanupScheduler(system);
Logger.info("Schedulers started");
}
private void startImagesCleanupScheduler(ActorSystem system) {
system.scheduler().schedule(
Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay
Duration.create(1, TimeUnit.DAYS), //Frequency 1 days
() -> {
//int rows = imageService.cleanupInactiveImages();
rows = 1;
Logger.info(String.format("%d inactive unused images cleaned from db", rows ));
},
system.dispatcher()
);
}
}
然后创建模块:
public class OnStartupModule extends AbstractModule {
@Override
public void configure() {
bind(OnStartup.class).asEagerSingleton();
}
}
最终在 application.conf 中启用模块:
play.modules.enabled += "modules.OnStartupModule"
这对于评论来说有点太长了,但我没有测试这种方法,你可能需要调整它。文档说组件的销毁顺序与它们创建的顺序相反。这意味着您可能会在 ActorSystem
关闭之前取消您的调度程序,因为此 class 在它之后注册并依赖于它。在您的 OnStartup
class 中创建一个这样的关闭挂钩,您将在其中取消您的日程安排。这意味着在 ActorSystem
关闭时,将没有要执行的计划:
@Singleton
public class OnStartup {
private final Cancellable cancellableSchedule;
@Inject
public OnStartup(final ActorSystem system, final ApplicationLifecycle l) {
cancellableSchedule = startScheduler(system);
initStopHook(l);
}
private Cancellable startScheduler(final ActorSystem system) {
return startImagesCleanupScheduler(system);
Logger.info("Schedulers started");
}
private Cancellable startImagesCleanupScheduler(ActorSystem system) {
return system.scheduler().schedule(
Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay
Duration.create(1, TimeUnit.DAYS), //Frequency 1 days
() -> {
//int rows = imageService.cleanupInactiveImages();
rows = 1;
Logger.info(String.format("%d inactive unused images cleaned from db", rows ));
},
system.dispatcher()
);
}
private void initStopHook(ApplicationLifecycle lifecycle) {
lifecycle.addStopHook(() -> {
cancellableSchedule.cancel();
return CompletableFuture.completedFuture(null);
});
}
}
我在播放应用程序服务器启动时启动的调度程序有问题,但是一旦应用程序关闭,它就会遇到以下代码部分:
// firstDay something like 1 = monday
private void startScheduler(final ImageService imageService,
final ActorSystem system) {
startImagesCleanupScheduler(imageService, system);
Logger.info("Schedulers started");
}
我的问题是 Runnable
块立即开始执行,而不是仅仅取消任务。
澄清代码:
以下方法启动Scheduler
:
private void startImagesCleanupScheduler(ImageService imageService, ActorSystem system) {
system.scheduler().schedule(
Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay
Duration.create(1, TimeUnit.DAYS), //Frequency 1 days
() -> {
int rows = imageService.cleanupInactiveImages();
Logger.info(String.format("%d inactive unused images cleaned from db", rows));
},
system.dispatcher()
);
}
关机时的日志请注意这里的第一行:
[info] - application - 1 inactive unused images cleaned from db
[info] - application - Shutting down connection pool.
[info] - application - Creating Pool for datasource 'default'
...
[info] - application - Schedulers started
[info] - play.api.Play - Application started (Prod)
你可以看到它执行了调度程序,忽略了它原来的执行时间,然后关闭,然后启动,"Schedulers started" 之后。
什么问题,我如何取消调度程序或防止在关机前播放到 运行?这是 Akka 的错误吗?
我在 OnStartup
内调用 startScheduler
就像下面问题的答案一样:
编辑: 以下是重现问题的最少代码:
首先创建OnStartup
class:
@Singleton
public class OnStartup {
@Inject
public OnStartup(final ActorSystem system) {
startScheduler(system);
}
private void startScheduler(final ActorSystem system) {
startImagesCleanupScheduler(system);
Logger.info("Schedulers started");
}
private void startImagesCleanupScheduler(ActorSystem system) {
system.scheduler().schedule(
Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay
Duration.create(1, TimeUnit.DAYS), //Frequency 1 days
() -> {
//int rows = imageService.cleanupInactiveImages();
rows = 1;
Logger.info(String.format("%d inactive unused images cleaned from db", rows ));
},
system.dispatcher()
);
}
}
然后创建模块:
public class OnStartupModule extends AbstractModule {
@Override
public void configure() {
bind(OnStartup.class).asEagerSingleton();
}
}
最终在 application.conf 中启用模块:
play.modules.enabled += "modules.OnStartupModule"
这对于评论来说有点太长了,但我没有测试这种方法,你可能需要调整它。文档说组件的销毁顺序与它们创建的顺序相反。这意味着您可能会在 ActorSystem
关闭之前取消您的调度程序,因为此 class 在它之后注册并依赖于它。在您的 OnStartup
class 中创建一个这样的关闭挂钩,您将在其中取消您的日程安排。这意味着在 ActorSystem
关闭时,将没有要执行的计划:
@Singleton
public class OnStartup {
private final Cancellable cancellableSchedule;
@Inject
public OnStartup(final ActorSystem system, final ApplicationLifecycle l) {
cancellableSchedule = startScheduler(system);
initStopHook(l);
}
private Cancellable startScheduler(final ActorSystem system) {
return startImagesCleanupScheduler(system);
Logger.info("Schedulers started");
}
private Cancellable startImagesCleanupScheduler(ActorSystem system) {
return system.scheduler().schedule(
Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay
Duration.create(1, TimeUnit.DAYS), //Frequency 1 days
() -> {
//int rows = imageService.cleanupInactiveImages();
rows = 1;
Logger.info(String.format("%d inactive unused images cleaned from db", rows ));
},
system.dispatcher()
);
}
private void initStopHook(ApplicationLifecycle lifecycle) {
lifecycle.addStopHook(() -> {
cancellableSchedule.cancel();
return CompletableFuture.completedFuture(null);
});
}
}