首页
使用 Play
常见主题
调度任务
§ 调度异步任务
您可以调度向 Actor 发送消息和执行任务(函数或 Runnable
实例)。您将获得一个 Cancellable
,您可以对其调用 cancel
来取消计划操作的执行。
例如,要每 30 秒向 testActor
发送一条消息
Scala
/*
* Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>
*/
package tasks
import javax . inject . Inject
import javax . inject . Named
import scala . concurrent . duration . _
import scala . concurrent . ExecutionContext
import org . apache . pekko . actor . ActorRef
import org . apache . pekko . actor . ActorSystem
class MyActorTask @Inject () ( actorSystem : ActorSystem , @Named ( "some-actor" ) someActor : ActorRef )(
implicit executionContext : ExecutionContext
) {
actorSystem . scheduler . scheduleAtFixedRate (
initialDelay = 0.microseconds ,
interval = 30.seconds ,
receiver = someActor ,
message = "tick"
)
}
Java
/*
* Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>
*/
package tasks ;
import java . util . concurrent . TimeUnit ;
import javax . inject . Inject ;
import javax . inject . Named ;
import org . apache . pekko . actor . ActorRef ;
import org . apache . pekko . actor . ActorSystem ;
import scala . concurrent . ExecutionContext ;
import scala . concurrent . duration . Duration ;
public class MyActorTask {
private final ActorRef someActor ;
private final ActorSystem actorSystem ;
private final ExecutionContext executionContext ;
@Inject
public MyActorTask (
@Named ( "some-actor" ) ActorRef someActor ,
ActorSystem actorSystem ,
ExecutionContext executionContext ) {
this . someActor = someActor ;
this . actorSystem = actorSystem ;
this . executionContext = executionContext ;
this . initialize ();
}
private void initialize () {
actorSystem
. scheduler ()
. scheduleAtFixedRate (
Duration . create ( 0 , TimeUnit . SECONDS ), // initialDelay
Duration . create ( 30 , TimeUnit . SECONDS ), // interval
someActor ,
"tick" , // message,
executionContext ,
ActorRef . noSender ());
}
}
注意: 有关如何注入 Actor 的信息,请参阅 Scala 或 Java 文档。
类似地,要从现在起 10 秒后每分钟运行一段代码
Scala
class CodeBlockTask @Inject () ( actorSystem : ActorSystem )( implicit executionContext : ExecutionContext ) {
actorSystem . scheduler . scheduleAtFixedRate ( initialDelay = 10.seconds , interval = 1.minute ) { () =>
// the block of code that will be executed
actorSystem . log . info ( "Executing something..." )
}
}
Java
public class CodeBlockTask {
private final ActorSystem actorSystem ;
private final ExecutionContext executionContext ;
@Inject
public CodeBlockTask ( ActorSystem actorSystem , ExecutionContext executionContext ) {
this . actorSystem = actorSystem ;
this . executionContext = executionContext ;
this . initialize ();
}
private void initialize () {
this . actorSystem
. scheduler ()
. scheduleAtFixedRate (
Duration . create ( 10 , TimeUnit . SECONDS ), // initialDelay
Duration . create ( 1 , TimeUnit . MINUTES ), // interval
() -> actorSystem . log (). info ( "Running block of code" ),
this . executionContext );
}
}
或者要从现在起 10 秒后运行一次代码
Scala
class ScheduleOnceTask @Inject () ( actorSystem : ActorSystem )( implicit executionContext : ExecutionContext ) {
actorSystem . scheduler . scheduleOnce ( delay = 10.seconds ) { () =>
// the block of code that will be executed
actorSystem . log . info ( "Executing something..." )
}
}
Java
/*
* Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>
*/
private final ActorSystem actorSystem ;
private final ExecutionContext executionContext ;
@Inject
public CodeBlockOnceTask ( ActorSystem actorSystem , ExecutionContext executionContext ) {
this . actorSystem = actorSystem ;
this . executionContext = executionContext ;
this . initialize ();
}
private void initialize () {
this . actorSystem
. scheduler ()
. scheduleOnce (
Duration . create ( 10 , TimeUnit . SECONDS ), // delay
() -> System . out . println ( "Running just once." ),
this . executionContext );
}
}
您可以查看 Pekko 文档以查看调度程序的其他可能用途。请参阅 pekko.actor.Scheduler
的 Scala 文档 或 Java 文档 。
注意 :您可以创建 CustomExecutionContext
,而不是使用默认的 ExecutionContext
。请参阅 Java 文档 或 Scala 文档 。请参阅下面的相关部分。
§ 在应用程序启动时启动任务
在定义完上述任务后,您需要在应用程序启动时初始化它们。
§ 使用 Guice 依赖注入
当使用 Guice 依赖注入时,您需要创建一个模块并启用它,以便将任务加载为 急切单例
Scala
/*
* Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>
*/
package tasks
import play . api . inject . _
import play . api . inject . SimpleModule
class TasksModule extends SimpleModule ( bind [ MyActorTask ]. toSelf . eagerly ())
Java
/*
* Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>
*/
package tasks ;
import com . google . inject . AbstractModule ;
public class TasksModule extends AbstractModule {
@Override
protected void configure () {
bind ( MyActorTask . class ). asEagerSingleton ();
}
}
然后在您的application.conf
中添加以下行以启用该模块
play . modules . enabled += "tasks.TasksModule"
由于任务定义与依赖注入框架完全集成,您也可以在其中注入任何必要的组件。有关如何使用 Guice 依赖注入的更多详细信息,请参阅Scala 或Java 文档。
§ 使用编译时依赖注入
使用编译时依赖注入时,您只需要在BuiltInComponents
的实现中启动它们即可
Scala
/*
* Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>
*/
package tasks
import play . api . routing . Router
import play . api . ApplicationLoader . Context
import play . api . BuiltInComponentsFromContext
import play . api . NoHttpFiltersComponents
class MyBuiltInComponentsFromContext ( context : Context )
extends BuiltInComponentsFromContext ( context )
with NoHttpFiltersComponents {
override def router : Router = Router . empty
// Task is initialize here
initialize ()
private def initialize (): Unit = {
new CodeBlockTask ( actorSystem )
}
}
Java
/*
* Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>
*/
package tasks ;
import play . ApplicationLoader ;
import play . BuiltInComponentsFromContext ;
import play . filters . components . NoHttpFiltersComponents ;
import play . routing . Router ;
public class MyBuiltInComponentsFromContext extends BuiltInComponentsFromContext
implements NoHttpFiltersComponents {
public MyBuiltInComponentsFromContext ( ApplicationLoader . Context context ) {
super ( context );
this . initialize ();
}
private void initialize () {
// Task is initialize here
new CodeBlockTask ( actorSystem (), executionContext ());
}
@Override
public Router router () {
return Router . empty ();
}
}
然后必须将其与您的自定义ApplicationLoader
实现一起使用。有关如何使用编译时依赖注入的更多详细信息,请参阅Scala 或Java 文档。
§ 使用CustomExecutionContext
创建执行同步/阻塞工作的任务时,应使用自定义执行上下文。例如,如果您的任务使用 JDBC 访问数据库,则它正在执行阻塞 I/O。如果您使用默认执行上下文,那么您的任务将阻塞用于接收和处理请求的线程。为了避免这种情况,您应该提供一个自定义执行上下文
Scala
import javax . inject . Inject
import org . apache . pekko . actor . ActorSystem
import play . api . libs . concurrent . CustomExecutionContext
class TasksCustomExecutionContext @Inject () ( actorSystem : ActorSystem )
extends CustomExecutionContext ( actorSystem , "tasks-dispatcher" )
Java
import java . util . concurrent . TimeUnit ;
import javax . inject . Inject ;
import org . apache . pekko . actor . ActorSystem ;
import play . libs . concurrent . CustomExecutionContext ;
import scala . concurrent . duration . Duration ;
public class TasksCustomExecutionContext extends CustomExecutionContext {
@Inject
public TasksCustomExecutionContext ( ActorSystem actorSystem ) {
super ( actorSystem , "tasks-dispatcher" );
}
}
使用tasks-dispatcher
作为线程池名称,按照线程池文档 中的描述配置线程池,然后将其注入到您的任务中
Scala
class SomeTask @Inject () ( actorSystem : ActorSystem , executor : TasksCustomExecutionContext ) {
actorSystem . scheduler . scheduleAtFixedRate ( initialDelay = 10.seconds , interval = 1.minute ) { () =>
actorSystem . log . info ( "Executing something..." )
}( executor ) // using the custom execution context
}
Java
public class SomeTask
private final ActorSystem actorSystem ;
private final TasksCustomExecutionContext executor ;
@Inject
public SomeTask ( ActorSystem actorSystem , TasksCustomExecutionContext executor ) {
this . actorSystem = actorSystem ;
this . executor = executor ;
this . initialize ();
}
private void initialize () {
this . actorSystem
. scheduler ()
. scheduleAtFixedRate (
Duration . create ( 10 , TimeUnit . SECONDS ), // initialDelay
Duration . create ( 1 , TimeUnit . MINUTES ), // interval
() -> actorSystem . log (). info ( "Running block of code" ),
this . executor // using the custom executor
);
}
}
§ 使用第三方模块
您还可以使用模块来调度任务。访问我们的模块目录 页面以查看可用模块的列表。
下一步: 应用程序关闭
在此文档中发现错误?此页面的源代码可以在此处 找到。阅读完文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?访问我们的社区论坛 ,与社区开始对话。