1. 概要

このチュートリアルでは、AkkaTypedを使用してアクターを検出または検出する方法について説明します。

Akkaクラシックでは、ActorSystemactorSelectionメソッドを簡単に呼び出すことができます。これにより、Actorへの参照が提供されます。 しかし、Akka Typedを使用すると、すぐに学習するように、これを別の方法で実現できます。

2. 序章

AkkaでActorモデルを使用してシステムを構築する場合、特定のタスクを実行させるには、個々のActorを識別できる必要があります。 場合によっては、メッセージ内の特定のActorへの参照を渡すことでこれを実現できます。

それが不可能な場合は、気になる特定のアクターを見つけたり発見したりできる必要があります。

例として、1つのマスターノードまたはアクターがあり、複数のワーカーノードまたはアクターがあるマスターワーカーアーキテクチャに従うシステムを構築する必要があると想像してください。 何らかの理由で、特定のワーカーの動作を要因に基づいて変更したい場合は、そのワーカーに別のことを実行させるか、シャットダウンするために、単一のワーカーを識別する必要があります。

Akka Typedを使用してそれを行うにはどうすればよいですか?

Akka Typedの導入により、アクターがどのように見つかるかを理解するための最も重要な部分は、受付係です。

受付係は、アクターが別のアクターによって発見される必要があるが、着信メッセージにそれへの参照を入れることができない場合に使用される、アクターシステムによって提供されるサービスです。

アクターを発見するには、ライフサイクルの開始で受付係に登録する必要があります。 

受付係を使用してアクターを見つける方法を説明するために、マスターワーカーアーキテクチャを使用する単純なアプリケーションを設計します。 このシステムでは、ワーカーをランダムに見つけようとします。簡単にするために、ワーカーはコンソールに何かを印刷するだけです。

3. 俳優登録

アクターを作成して受付に登録する方法を見てみましょう。

まず、 Worker Actor を作成し、Registerメッセージを受付係に送信します。

object Worker {
   sealed trait WorkerMessage
   object WorkerMessage {
    // simple message for workers to identify themselves
    case object IdentifyYourself extends WorkerMessage
   }
    
    // key to uniquely identify Worker actors
    val key  : ServiceKey[WorkerMessage] = ServiceKey("Worker")
    import WorkerMessage._
    def apply(id : Int) : Behavior[WorkerMessage] = Behaviors.setup { context =>
    
    // register actor with receptionist using the key and passing itself
    context.system.receptionist ! Receptionist.Register(key, context.self)
    Behaviors.receiveMessage {
      case IdentifyYourself =>
        println(s"Hello, I am worker $id")
        Behaviors.same
    }
  }
}

ここで行っていることを見ていきましょう。 まず、このメッセージの種類を定義しますワーカー俳優特性によって定義された、受け取ることができる WorkerMessage。 また、サービスキーを定義し、受付係に登録します。 次に、受付係はこのキーを使用して、アクターまたはアクターのグループを識別します。

ワーカーがIdentifyYourselfメッセージを受信すると、ワーカーIDをコンソールに出力するだけです。

4. アクターディスカバリー

アクターが受付係に自分自身を登録する方法を説明しました。 それでは、同じ受付係を使用してActorを見つける方法を見てみましょう。

これを行うには、マスター アクターを作成します。このジョブの仕事は、ワーカー アクターを起動し、検索することです。またはこれらの労働者を発見する:

 object Master {
   sealed trait MasterMessage
    
  object MasterMessage {
    case class StartWorkers(numWorker: Int) extends MasterMessage
    case class IdentifyWorker(id: Int) extends MasterMessage
    case object Done extends MasterMessage
    case object Failed extends MasterMessage
  }

  import MasterMessage._

  def workerName(id: Int) = {
    s"Worker-$id"
  }

  def apply(): Behavior[MasterMessage] = Behaviors.setup { context =>

    Behaviors.receiveMessage {
      case StartWorkers(numWorker) =>

        // spin up new workers
        for (id <- 0 to numWorker) {
          context.spawn(Worker(id), workerName(id))
        }
        Behaviors.same


      case IdentifyWorker(id) =>
        implicit val timeout: Timeout = 1.second
        context.ask(
          context.system.receptionist,
          Find(Worker.key) // ask the receptionist for actors with the key defined by Worker.key
        ) {
          case Success(listing: Listing) =>
            val workerInstances = listing.serviceInstances(Worker.key)

            // find worker with the correct id
            val maybeWorker = workerInstances.find { worker =>
              worker.path.name contentEquals workerName(id)
            }
            maybeWorker match {
              case Some(worker) =>
                worker ! Worker.WorkerMessage.IdentifyYourself
              case None =>
                println("worker not found ): ")
            }
            MasterMessage.Done

          case Failure(_) =>
            MasterMessage.Failed
        }

        Behaviors.same
    }
  }
}

アクター登録と同様に、マスター アクターを作成しました。これは、ワーカーアクターのいずれかのスポーンの役割を果たします。 sまたはIDでワーカーアクターを検索しようとしています。 ワーカーを特定するように求められた場合、最初に、ワーカーサービスキーに登録されているすべてのアクターを受付係に尋ねます。 ワーカーアクターのセットが返されます。

このWorkerActors のセットを取得すると、結果のセットから Actor の名前を確認することで、必要なActorを見つけることができます。 Actor が見つからない場合は、別のことを行うことができます。この場合、コンソールにメッセージを出力するだけです。

気になるActorが見つかった場合は、そのActorIdentifyYourselfメッセージを送信します。

ドライバープログラムは次のようになります。

// create the ActorSystem
val master: ActorSystem[MasterMessage] = ActorSystem(
  Master(),
  "master"
)

// send the StartWorker message to the Master Actor
master ! MasterMessage.StartWorkers(10)

// prints "Hello, I am worker 5"
master ! MasterMessage.IdentifyWorker(5)

5. 結論

この記事では、受付係がアクターを登録して見つける方法を見てきました。 アクターを使用してシステムを設計する場合、アクターをメッセージとして渡すことができない場合に受付係を利用してアクターを識別することができるため、これは強力なツールです。

いつものように、ソースコードはGitHubにあります。