按需演员获得否则创建(on demand actor get or else create)

2019-06-24 20:00发布

我可以创建角色actorOf ,并看着他们actorFor 。 我现在想通过一些演员id:String ,如果它不存在,我希望创建它。 事情是这样的:

  def getRCActor(id: String):ActorRef = {
    Logger.info("getting actor %s".format(id))
    var a = system.actorFor(id)
    if(a.isTerminated){
      Logger.info("actor is terminated, creating new one")
      return system.actorOf(Props[RC], id:String)
    }else{
      return a
    }
   }

但是,这并不因为工作isTerminated始终是真实的,我得到actor name 1 is not unique! 例外的第二个电话。 我想我在这里使用了错误的模式。 谁能帮如何实现这一目标? 我需要

  • 按需创建角色
  • 通过ID查找演员和如果不存在,创建它们
  • 能够摧毁,因为我不知道我是否会再需要它

我应该使用这样的调度员或路由器?

解决方案作为建议我用持有的可用角色在地图中的具体主管。 它可以被要求提供他的一个孩子。

class RCSupervisor extends Actor {

  implicit val timeout = Timeout(1 second)
  var as = Map.empty[String, ActorRef]

  def getRCActor(id: String) = as get id getOrElse {
    val c = context actorOf Props[RC]
    as += id -> c
    context watch c
    Logger.info("created actor")
    c
  }

  def receive = {

    case Find(id) => {
      sender ! getRCActor(id)
    }

    case Terminated(ref) => {
      Logger.info("actor terminated")
      as = as filterNot { case (_, v) => v == ref }
    }
  }
}

他的同伴对象

object RCSupervisor {

  // this is specific to Playframework (Play's default actor system)
  var supervisor = Akka.system.actorOf(Props[RCSupervisor])

  implicit val timeout = Timeout(1 second)

  def findA(id: String): ActorRef = {
    val f = (supervisor ? Find(id))
    Await.result(f, timeout.duration).asInstanceOf[ActorRef]
  }
  ...
}

Answer 1:

我一直没有使用阿卡那么久,但演员的创造者是默认他们的主管 。 因此,家长可以听他们的终止;

var as = Map.empty[String, ActorRef] 
def getRCActor(id: String) = as get id getOrElse {
  val c = context actorOf Props[RC]
  as += id -> c
  context watch c
  c
}

但显然你需要看他们的终止;

def receive = {
  case Terminated(ref) => as = as filterNot { case (_, v) => v == ref }

那是一个解决方案吗? 我必须说,我并没有完全明白你的意思“终止始终是真实的=>演员名1不是唯一的!”



Answer 2:

演员只能由他们的父母来创建,并从你的描述我假设你正在试图让系统创建一个非顶级的演员,这将永远失败。 你应该做的是将消息发送到父说:“给我的孩子在这里”,那么家长可以检查是否当前存在的,是身体健康等,有可能创建一个新的,然后用适当的回应结果消息。

要重申这一极其重要的一点:获取或创建永远只能通过直接父来完成。



Answer 3:

我根据我的解决方案对oxbow_lakes'代码/建议这个问题,但不是创建所有的孩子演员我用了一个(双向)地图,这可能是有益的,如果儿童演员的数量是显著的简单集合。

import play.api._
import akka.actor._
import scala.collection.mutable.Map 

trait ResponsibleActor[K] extends Actor {
  val keyActorRefMap: Map[K, ActorRef] = Map[K, ActorRef]()
  val actorRefKeyMap: Map[ActorRef, K] = Map[ActorRef, K]()

  def getOrCreateActor(key: K, props: => Props, name: => String): ActorRef = {
    keyActorRefMap get key match {
      case Some(ar) => ar
      case None =>  {
        val newRef: ActorRef = context.actorOf(props, name)
        //newRef shouldn't be present in the map already (if the key is different)
        actorRefKeyMap get newRef match{
          case Some(x) => throw new Exception{}
          case None =>
        }
        keyActorRefMap += Tuple2(key, newRef)
        actorRefKeyMap += Tuple2(newRef, key)
        newRef
      }
    }
  }

  def getOrCreateActorSimple(key: K, props: => Props): ActorRef = getOrCreateActor(key, props, key.toString)

  /**
   * method analogous to Actor's receive. Any subclasses should implement this method to handle all messages
   * except for the Terminate(ref) message passed from children
   */
  def responsibleReceive: Receive

  def receive: Receive = {
    case Terminated(ref) => {
      //removing both key and actor ref from both maps
      val pr: Option[Tuple2[K, ActorRef]] = for{
        key <- actorRefKeyMap.get(ref)
        reref <- keyActorRefMap.get(key)
      } yield (key, reref)

      pr match {
        case None => //error
        case Some((key, reref)) => {
          actorRefKeyMap -= ref
          keyActorRefMap -= key
        }
      }
    }
    case sth => responsibleReceive(sth)
  }
}

要使用此功能,您继承ResponsibleActor和实施responsibleReceive 。 注:该代码是尚未全面测试,可能仍然有一些问题。 我中省略一些错误处理,以提高可读性。



Answer 4:

目前,你可以用Guice的依赖注入阿卡,这是在解释http://www.lightbend.com/activator/template/activator-akka-scala-guice 。 你必须创建一个伴随模块的演员。 在它的配置方法,然后需要创建一个名为绑定到演员类和一些属性。 属性可以来自其中,例如,一个路由器被配置为演员的结构。 你也可以把路由器的配置在那里编程。 你需要的地方演员的引用您@Named(“actorname”)注入它。 在需要的时候配置的路由器创建一个演员实例。



文章来源: on demand actor get or else create
标签: scala akka