父Actor向子Actor发送消息时,如果父Actor在发送消息后停止,则消息将成为“死信”。

3
考虑以下代码示例(版本1)。在这里,父级演员(ActorA)向子演员(ActorB)发送消息,然后停止自己。由于父级演员自我停止,当负载高时,子演员甚至在从邮箱中获取邮件之前就死亡,因此消息成为“死信”(请参见下面的示例输出1)。
出于某种原因,我无法修改应用程序设计以删除父级演员的自我停止。
版本1
import akka.actor.Actor
import akka.actor.OneForOneStrategy
import akka.actor.SupervisorStrategy.Stop
import akka.actor.Props
import akka.actor.ActorSystem

object AkkaTest extends App {

  val system = ActorSystem("AkkaTest")

  for (i <- 1 to 5) {
    system.actorOf(Props[ActorA]) ! i  
  }

}

class ActorA extends Actor {

  def receive = {
    case i: Int => { 
      context.actorOf(Props[ActorB]) ! i
      context.stop(self)
    }
  }

  override def postStop = println("ActorA - stopped")

}

class ActorB extends Actor {

  def receive = {
    case i: Int => {
      println("ActorB - processing msg - " + i)
    }
  }

  override def postStop = println("ActorB - stopped")

}

样例输出 1

ActorB - processing msg - 2
ActorB - processing msg - 1
ActorB - stopped
ActorB - stopped
ActorB - stopped
ActorB - stopped
ActorB - processing msg - 3
ActorB - stopped
ActorA - stopped
ActorA - stopped
[INFO] [09/09/2014 08:26:56.101] [AkkaTest-akka.actor.default-dispatcher-6] [akka://AkkaTest/user/$e/$a] Message [java.lang.Integer] from Actor[akka://AkkaTest/user/$e#-289783076] to Actor[akka://AkkaTest/user/$e/$a#-86921027] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
[INFO] [09/09/2014 08:26:56.101] [AkkaTest-akka.actor.default-dispatcher-3] [akka://AkkaTest/user/$d/$a] Message [java.lang.Integer] from Actor[akka://AkkaTest/user/$d#-1255514179] to Actor[akka://AkkaTest/user/$d/$a#402128903] was not delivered. [2] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
ActorA - stopped
ActorA - stopped
ActorA - stopped

现在考虑下面的代码修改(版本2)。通过从子actor到父actor的消息确认,然后在收到这个确认后自行停止父actor,可以摆脱死信问题(请参见样本输出2)。

版本2

import akka.actor.Actor
import akka.actor.OneForOneStrategy
import akka.actor.SupervisorStrategy.Stop
import akka.actor.Props
import akka.actor.ActorSystem

object AkkaTest extends App {

  val system = ActorSystem("AkkaTest")

  for (i <- 1 to 5) {
    system.actorOf(Props[ActorA]) ! i  
  }

}

class ActorA extends Actor {

  def receive = {
    case i: Int => context.actorOf(Props[ActorB]) ! i
    case m: MsgAck => context.stop(self) 
  }

  override def postStop = println("ActorA - stopped")

}

class ActorB extends Actor {

  def receive = {
    case i: Int => {
      sender ! MsgAck()
      println("ActorB - processing msg - " + i)
    }
  }

  override def postStop = println("ActorB - stopped")

}

case class MsgAck()

样例输出2

ActorB - processing msg - 4
ActorB - processing msg - 2
ActorB - processing msg - 5
ActorB - processing msg - 3
ActorB - processing msg - 1
ActorB - stopped
ActorB - stopped
ActorB - stopped
ActorB - stopped
ActorB - stopped
ActorA - stopped
ActorA - stopped
ActorA - stopped
ActorA - stopped
ActorA - stopped

现在我的问题是,是否有其他方法来实现相同的目的?我的意思是摆脱死信。
1个回答

1
当父进程停止时,其所有子进程也将停止。这会导致死信的产生。唯一确保没有死信的方法是确保父进程在子进程接收到消息之前仍然存活。我想不出其他方法,除了使用 "ack" 消息。

正如我所说,由于某些限制,我无法修改应用程序设计以消除父级演员的自我停止。无论如何,感谢您的回答。 - Kapil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接