阿卡:第一条消息传到死信,从第二条消息来看,一切都很好

时间:2017-11-17 14:45:37

标签: scala akka

我有主管演员根据收到的命令选择儿童演员,每当它创建一个新的儿童演员并且发送消息(询问模式)它超时作为儿童演员试图发回反应但是它去死信。

这是儿童演员代码

class IdActor(id: String, injector: Injector) extends Actor {
  override def receive: Receive = {
    case cmd: GenerateIdCmd =>
      val parent = sender()
      ...
      Future(idEvent) pipeTo sender //Issue is here going to dead letters
      //Future(idEvent) pipeTo parent //This also leads to same problem
      //parent ! idEvent // Same issue
  }
}

这是主管代码

class IdSupervisor(injector: Injector) extends Actor {
  override def receive: Receive = {
    case cmd: GenerateIdCmd =>
      ...
      val ref = context.child(cmd.id).getOrElse {
        context.actorOf(Props(classOf[IdActor], cmd.id, injector), cmd.id)
      }
      ask(ref, cmd) pipeTo sender
  }
}

第二条消息正在流回始发者,所有新的儿童演员的第一个回应是从那里开始致死的信件。

工作解决方案 问题在于Supervisor,固定代码

class IdSupervisor(injector: Injector) extends Actor {
      override def receive: Receive = {
        case cmd: GenerateIdCmd =>
          val originator = sender
          ...
          val ref = context.child(cmd.id).getOrElse {
            context.actorOf(Props(classOf[IdActor], cmd.id, injector), cmd.id)
          }
          ask(ref, cmd) pipeTo originator
      }
    }

2 个答案:

答案 0 :(得分:1)

永远不会从未来的演员内部直接发送给发件人,senderdef,并且在未来完成时,它可能已经不同于您的预期。解决方案之一是在将来调用之前存储发件人:

class IdActor(id: String, injector: Injector) extends Actor {
  override def receive: Receive = {
    case cmd: GenerateIdCmd =>
      ...
      val originalSender = sender
      Future(idEvent) pipeTo originalSender
  }
}

答案 1 :(得分:1)

我怀疑当孩子按照你的描述答复父母时,实际上并没有发生这个问题,但是当父母向孩子发送信息并希望得到回复时:

val ref = context.child(cmd.id).getOrElse {
  context.actorOf(Props(classOf[IdActor], cmd.id, injector), cmd.id)
}
ask(ref, cmd) pipeTo sender

actor在创建时异步启动。观察到,当创建一个新子节点时,该子节点的第一条消息会导致死信,而后续消息传递给该子节点会产生预期行为,这表明了一个actor初始化问题。可能发生的事情是,儿童演员在完全开始之前收到他们的第一条GenerateIdCmd消息。