ドキュメント

§非同期タスクのスケジューリング

アクターへのメッセージ送信とタスク(関数または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());
  }
}

注:アクターを注入する方法については、ScalaまたはJavaのドキュメントを参照してください。

同様に、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
            );
  }
}

§サードパーティモジュールの使用

タスクのスケジューリングに使用できるモジュールもあります。利用可能なモジュールのリストについては、モジュールディレクトリページをご覧ください。

次:アプリケーションのシャットダウン


このドキュメントに誤りを見つけましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインをお読みいただいた後、プルリクエストをお送りください。質問やアドバイスがありましたら、コミュニティフォーラムにアクセスして、コミュニティとの会話を始めてください。