§调度异步任务
您可以调度向 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()); } }
类似地,要从现在起 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 ); } }
§使用第三方模块
您还可以使用模块来调度任务。访问我们的模块目录页面以查看可用模块的列表。
下一步:应用程序关闭
在此文档中发现错误?此页面的源代码可以在此处找到。阅读完文档指南后,请随时贡献拉取请求。有疑问或建议要分享?访问我们的社区论坛,与社区开始对话。