§非同期タスクのスケジューリング
アクターへのメッセージ送信とタスク(関数またはRunnable
インスタンス)の実行をスケジュールできます。スケジュールされた操作の実行をキャンセルするためにcancel
を呼び出すことができるCancellable
が返されます。
たとえば、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秒後から1分ごとにコードブロックを実行するには、次のようにします。
- 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秒後にコードブロックを1回だけ実行するには、次のようにします。
- 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のドキュメントを参照してください。Scala向けpekko.actor.Scheduler
またはJava向けのドキュメントを参照してください。
注:デフォルトの
ExecutionContext
を使用する代わりに、CustomExecutionContext
を作成できます。JavaまたはScalaのドキュメントを参照してください。以下のセクションを参照してください。
§アプリケーション起動時のタスクの開始
上記のようにタスクを定義した後、アプリケーションの起動時に初期化する必要があります。
§Guice依存性注入の使用
Guice依存性注入を使用する場合、eagerシングルトンとしてタスクを読み込むモジュールを作成して有効にする必要があります。
- 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 ); } }
§サードパーティモジュールの使用
タスクのスケジューリングに使用できるモジュールもあります。利用可能なモジュールのリストについては、モジュールディレクトリページをご覧ください。
このドキュメントに誤りを見つけましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインをお読みいただいた後、プルリクエストをお送りください。質問やアドバイスがありましたら、コミュニティフォーラムにアクセスして、コミュニティとの会話を始めてください。