我已经制作了以下代码:
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
?
答案 0 :(得分:2)
这与死信无关,请参阅Message Delivery Reliability。在Akka中,当使用In-JVM消息传递时 - 您可以保证在大多数情况下将以高概率传递消息(在异常之后重新启动)。无法传递的消息(如自愿停止或从未存在过的演员的消息)将进入DeadLetters框,但您应该明确订阅它们,这不是您在这里。您刚收到来自您自己的演员邮箱的消息(因为在重新启动期间没有删除框 - 只有演员的实例)。您需要明确订阅相应的Event Stream以观看deadLetters。
您无法在context.stop(self)
内处理supervisorStrategy
,因为它的自愿终止(实际上会导致邮件进入死信)并非例外情况(失败)。因此1/0
和context.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自己可以弥补的事情(两者都没有 我们写的是“做我的意思”框架,你也不希望我们这样做。