2

我制作了以下代码:

package com.star.wars

import akka.actor._
import akka.actor.SupervisorStrategy._
import akka.util.duration._

object Test extends App {

  case object Kill
  case object Create

  class Luke extends Actor {

    var x: Int = 0

    println("Luke here")
    Thread.sleep(1000)
    println("Luke here2")

    def receive = {
      case Kill => 1/0// context.stop(self)
      case msg: String => {
        x += 1
        println(x + msg)
      }
    }

  }

  class Vader extends Actor {

    println("Vader here")

    override val supervisorStrategy =
      OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
        case _: ArithmeticException      => Restart
        case _: NullPointerException     => Restart
        case _: IllegalArgumentException => Restart
        case _: Exception                => Restart
      }

    def receive = {
      case Create => context.actorOf(Props(new Luke), name = "Luke")
      case Kill => {
        val luke = context.actorFor("/user/Vader/Luke")
        luke ! "Pre hi there"
        luke ! Kill
        luke ! "Post hi there"
        println("Pre -> Kill -> Post sent to Luke")
      }
    }

  }

  val system = ActorSystem("MySystem")
  val vader = system.actorOf(Props(new Vader), name = "Vader")
  vader ! Create
  vader ! Kill
  println("Create -> Kill sent to Vader")

}

这段代码的目的,是为了证明,当 Luke 重启时,他的死信箱可以接收消息,当 Luke 再次上线时,他可以接收到他不在时发送给他的消息。

输出似乎还可以。这在某种程度上是一个证明:

Create -> Kill sent to Vader
Vader here
Luke here
Pre -> Kill -> Post sent to Luke
Luke here2
1Pre hi there
[ERROR] [01/12/2015 00:32:02.74] [MySystem-akka.actor.default-dispatcher-3] [akka://MySystem/user/Vader/Luke] / by zero
java.lang.ArithmeticException: / by zero
    at com.sconysoft.robocode.Test$Luke$$anonfun$receive$1.apply(test.scala:21)
    at com.sconysoft.robocode.Test$Luke$$anonfun$receive$1.apply(test.scala:20)
    at akka.actor.Actor$class.apply(Actor.scala:318)
    at com.sconysoft.robocode.Test$Luke.apply(test.scala:12)
    at akka.actor.ActorCell.invoke(ActorCell.scala:626)
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:197)
    at akka.dispatch.Mailbox.run(Mailbox.scala:179)
    at akka.dispatch.ForkJoinExecutorConfigurator$MailboxExecutionTask.exec(AbstractDispatcher.scala:516)
    at akka.jsr166y.ForkJoinTask.doExec(ForkJoinTask.java:259)
    at akka.jsr166y.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975)
    at akka.jsr166y.ForkJoinPool.runWorker(ForkJoinPool.java:1479)
    at akka.jsr166y.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104)

Luke here
Luke here2
1Post hi there

但是,我不确定这是否总是正确的。我在akka文档中找不到它,所以我的推理可以吗?死信箱可以在akka中重复使用吗(演员重启后)?

顺便提一句。我该如何处理context.stop(self)维德的卢克supervisorStrategy

4

1 回答 1

2

这与死信无关,请参阅消息传递可靠性。在 Akka 中,当使用 In-JVM-messaging 时 - 您可以保证在大多数情况下消息将以高概率传递(异常后重新启动就是其中之一)。无法传递的消息(如发送给自愿停止或从未存在的参与者的消息)将进入 DeadLetters 框,但您应该明确订阅它们,这不是您在这里得到的。您刚刚收到了来自您自己的演员邮箱的消息(因为在重新启动期间没有删除盒子 - 只有演员的实例)。您需要显式订阅相应的Event Stream才能观看 deadLetters。

您无法context.stop(self)在内部进行处理,supervisorStrategy因为它是自愿终止(这实际上会导致消息变为 deadLetters)而不是异常情况(失败)。所以1/0context.stop(self)非常不同。对于监听孩子的生命周期,请参阅 -生命周期监控意味着什么

例如,让我们看看如果你真的把context.stop(self)代码而不是1/0

Luke here
Pre -> Kill -> Post sent to Luke
Luke here2
1Pre hi there
[INFO] [01/12/2015 09:20:37.325] [MySystem-akka.actor.default-dispatcher-4] [akka://MySystem/user/Vader/Luke] Message [java.lang.String] from Actor[akka://MySystem/user/Vader#-1749418461] to Actor[akka://MySystem/user/Vader/Luke#-1436540331] 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'.

所以这就是使用deadLetters邮箱的地方(“在日志中没有传递blabla”)。

无论如何,任何交付(包括死信,因为它只是一个合成参与者)都是基于JVM 内消息传递的尽力而为原则,因此没有绝对的保证:

Akka 测试套件依赖于不丢失本地上下文中的消息(对于非错误条件测试也适用于远程部署),这意味着我们确实尽最大努力保持测试稳定。然而,本地告诉操作可能会失败,原因与 JVM 上的普通方法调用相同:

  • 堆栈溢出错误
  • 内存不足错误
  • 其他 VirtualMachineError

此外,本地发送可能会以 Akka 特定的方式失败:

  • 如果邮箱不接受消息(例如完整的BoundedMailbox)
  • 如果接收参与者在处理消息时失败或已经终止

虽然第一个显然是配置问题,但第二个值得考虑:如果在处理过程中出现异常,消息的发送者不会得到反馈,而是将通知发送给主管。这通常与外部观察者的丢失消息无法区分。

在网络消息传递的情况下,您根本没有交付保证。卢克永远不知道他的父亲是谁。为什么?因为它更快,实际上没有人需要可靠的消息传递

发送者知道交互是否成功的唯一有意义的方法是接收业务级别的确认消息,这不是 Akka 可以自己弥补的(我们也不会编写“按我的意思做”框架,也不会您希望我们这样做)。

于 2015-01-12T02:06:16.277 回答