死信箱是否可以在akka重复使用?

时间:2015-01-11 23:48:57

标签: scala akka akka-supervision

我已经制作了以下代码:

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中重复使用(演员重启后)?

顺便说一下。如何处理Vader context.stop(self)中的Luke supervisorStrategy

1 个答案:

答案 0 :(得分:2)

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

您无法在context.stop(self)内处理supervisorStrategy,因为它的自愿终止(实际上会导致邮件进入死信)并非例外情况(失败)。因此1/0context.stop(self)非常不同。对于聆听孩子的生命周期,请参阅 - What Lifecycle Monitoring Means

例如,让我们看看如果您真正将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未送达"在日志记录中)。

无论如何,任何传递(包括死信,因为它只是一个合成的actor)都基于尽力而为原则用于in-JVM消息传递,所以没有绝对保证:< / p>

  

Akka测试套件依赖于不丢失本地环境中的消息   (对于远程部署的非错误条件测试),   这意味着我们确实尽最大努力来保持我们的测试   稳定。然而,本地tell操作可能由于同样的原因而失败   作为普通方法,可以在JVM上调用:

     
      
  • 的StackOverflowError
  •   
  • 的OutOfMemoryError
  •   
  • 其他VirtualMachineError
  •   
     

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

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

虽然第一个显然是第二个配置问题   值得一些思考:消息的发送者不会得到反馈   如果处理时有异常,则通知进入   而是主管。这通常与a无法区分   失去了外面观察者的信息。

如果是网络消息,您根本没有送货保证。卢克永远不知道谁是他的父亲。为什么?因为它更快且实际上Nobody Needs Reliable Messaging

  

发件人了解互动的唯一有意义的方式   成功是通过接收业务级别的确认   消息,这不是Akka自己可以弥补的事情(两者都没有   我们写的是“做我的意思”框架,你也不希望我们这样做。