Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to construct an actor together with its wrapper?

Tags:

scala

akka

I'm trying to write an actor called ActorManager which wraps another actor called RealActor. The idea is that the ActorManager can process all messages going in and out of RealActor, allowing to add additional logic like filtering or buffering. The outside world is supposed to communicate with the RealActor only through its manager, much like in real world.

A first draft would look like this:

class ActorManager(realActor: ActorRef) extends Actor {
  def receive = {
    case _ => { /* pre-process messages */ }
  }
}

class RealActor(actorManager: ActorRef) extends Actor {
  def receive = {
    case _ => { /* actual business logic */ }
  }
}

This however raises the question how to construct both actors at once, or more specifically how to define the corresponding Props given the circular dependency of the two actors. I'm not sure if the general lazy val pattern is applicable when defining Props.

I also would like to avoid the work-around of constructing one of the two first, combined with introducing an explicit Register protocol to connect them.

like image 599
bluenote10 Avatar asked Mar 24 '17 14:03

bluenote10


Video Answer


2 Answers

Such a case is much better solved by using an actor hierarchy instead of plain actor siblings. Since the main intent here is to hide the RealActor from the outside world, it makes much more sense that its ActorRef is accordingly wrapped/owned by the outer ActorManager.

This means that the RealActor reference has to be created within the ActorManager scope. This can be achieved by passing the parent an ActorRef => Props function, allowing to create the child actor:

// Parent
class ActorManager(getRealActorProps: ActorRef => Props) extends Actor {
  val realActor = context.actorOf(getRealActorProps(self))
  def receive = {
    case _ => { /* pre-process messages */ }
  }
}

// Child
class RealActor(actorManager: ActorRef) extends Actor {
  def receive = {
    case _ => { /* actual business logic */ }
  }
}

object RealActor {
  def propsActorManager(getRealActorProps: ActorRef => Props) = 
    Props(new ActorManager(getRealActorProps))
  def propsRealActor(actorManager: ActorRef) = 
    Props(new RealActor(actorManager))

  def props() = 
    Props(new ActorManager(actorManager => propsRealActor(actorManager)))
}

Note that it is now even possible to hide the fact that the RealActor is wrapped by providing an appropriate props definition, which builds the ActorManager -> RealActor hierarchy implicitly.

See also this blog post why flat actor hierarchies are considered an anti-pattern.

like image 71
bluenote10 Avatar answered Nov 03 '22 00:11

bluenote10


Something of this sort may work well for you:

import akka.actor._

class Manager extends Actor {

  def realActor: ActorRef = context.child("real")
        .getOrElse(context.actorOf(RealActor.props, "real"))

  override def receive: Receive = {
    case msg ⇒ realActor forward msg
  }
}    

object RealActor {
  def props: Props = Props(new RealActor)
}

class RealActor extends Actor {
  override def receive: Receive = {
    case _ ⇒
  }
}

Creating child actor through parent's context seems to be sufficient for creating parent-child hierarchy. The parent can be obtained by calling context.parent in child actor.

like image 20
Tomasz Perek Avatar answered Nov 03 '22 00:11

Tomasz Perek