Akka - 共同服务人员:识别或扩展

时间:2013-06-09 12:48:49

标签: scala akka actor identify

让我说我有一些其他演员服务层演员常用的。例如,存储和检索域对象的注册表服务:

case class DomainObject(id: UUID)

class Registry extends akka.actor.Actor {
  def receive: Receive = {
    case o: DomainObject => store(o) // save or update object

    case id: UUID => sender ! retrieve(id) // retrieve object and send it back
  }
}

我不想将此类注册表的实例明确传递给可能使用它的所有actor。而不是它,我希望他们能够以某种方式“找到”它。

为此我可以想到两个解决方案:

  1. Identify消息:每个注册管理机构用户actor都知道某些配置中的注册管理机构名称,并且能够向其发送标识消息。收到AgentIdentity消息后,我们很高兴:

    val registryName = ... // some name
    val registryId = ... // some id
    var registry = _
    
    def preStart() {
      context.actorSelection(registryName) ! Identify(registryId)
    }
    
    def receive: Receive = {
      case ActorIdentity(`registryId`, ref) => registry = ref
    }
    

    我不喜欢这种方式,因为在用户演员初始化之后有一个阶段,当我们不知道系统中是否有注册表,因此我们不知道我们是否能够操作。

  2. Akka Extensions:我可以创建一个扩展名:

    一个。在初始化时在给定的Actor System中创建Registry actor的实例;

    湾通过Extension中的某些方法将此actor返回给需要它的用户。

    object RegistryKey extends ExtensionKey[RegistryExtension]
    
    class RegistryExtesion(system: ExtendedActorSystem) extends RegistryKey {
      val registry = system.actorOf(Props[Registry], "registry")
    }
    
  3. 问题是:哪种方法更好,Akka Extesions可以用于此吗?

2 个答案:

答案 0 :(得分:3)

我认为扩展的想法是好的,只要你的注册表演员总是在同一个ActorSystem

或者,使用actorSelection(改编自Remote Lookup):

class RegistryClient extends Actor {
  val path = "/path/to/registry/actor"
  context.setReceiveTimeout(3.seconds)

  def sendIdentifyRequest(): Unit =
    context.actorSelection(path) ! Identify(path)

  def receive = {
    case ActorIdentity(`path`, Some(ref)) ⇒
      context.setReceiveTimeout(Duration.Undefined)
      context.become(active(ref))
    case ActorIdentity(`path`, None) ⇒
      throw new RuntimeException("Registry not found")
    case ReceiveTimeout ⇒ sendIdentifyRequest() 
  }

  def active(registry: ActorRef): Actor.Receive = {
    // use the registry
  }
}

这适用于远程或本地演员。

让我们来看看扩展解决方案。 Actors are created asynchronously。因此,如果actor无法初始化,则在调用actorOf时,扩展构造函数不会失败。

如果你想确定演员未能初始化,那么一种了解方法就是ask演员将会回复并Await作出回应。如果演员没有回复,Await将抛出TimeoutException

class RegistryExtension(system: ExtendedActorSystem) extends Extension {
  val registry = system.actorOf(Props[Registry], "registry")
  implicit val timeout: Timeout = Timeout(500.millis)
  val f = registry ? "ping"    // Registry should case "ping" => "pong" 
  Await.result(f, 500.millis)  // Will throw a TimeoutException if registry fails 
                               // to respond
}

第一次拨打TimeoutException时,RegistryExtension(system).registry会被抛出。

答案 1 :(得分:3)

Cake Pattern或依赖注入库如subcut如何。

Derek Wyatt在他的书“Akka Concurrency”中提到DI,而不是使用太多的演员来查找演员: http://www.artima.com/forums/flat.jsp?forum=289&thread=347118