为什么我的sender()DeadLetters来自计划的邮件? [英] Why is my sender() DeadLetters from a scheduled message?
问题描述
我正在尝试安排一段时间后要发送的消息-简单的重试.
I am trying to schedule a message to be sent after a period of time - a simple retry.
override def receive = {
case Worked => ???
case DidNotWork =>
val target = sender() // Avoid closing over sender().
import context._
context.system.scheduler.scheduleOnce(500.milliseconds, target, TryAgain)
}
这按预期方式工作,但是,当我收到TryAgain
消息并访问sender()
尝试将此ActorRef
获取到该对象时,我得到了DeadLetters
.为什么会这样?
This works as expected, however, when I receive the TryAgain
message, and access sender()
to try and get this ActorRef
to this object, I get DeadLetters
. Why is this happening?
(请注意,问题出在另一个actor中的sender()
调用中,该调用不在关闭中-这不是我要关闭sender()
的问题):
(Note that the problem is the sender()
call in the other actor, which is not in a closure - this is not a problem where I'm closing over sender()
):
override def receive = {
case TryOnce => sender() ! DidNotWork
case TryAgain => sender() ! Worked // sender() here is DeadLetters!
}
完整示例(响应 cmbaxter的评论):
import akka.actor.{Props, ActorSystem, Actor}
import scala.concurrent.duration._
object Main {
def main(args: Array[String]) {
val sys = ActorSystem("Test")
val test = sys.actorOf(Props[Test], "test-actor")
test ! "badtest"
test ! "goodtest"
}
}
class Test extends Actor {
override def receive = {
case "badtest" =>
import context._
context.system.scheduler.scheduleOnce(10.milliseconds, this.self, "bad")
case "goodtest" =>
import context.dispatcher
context.system.scheduler.scheduleOnce(10.milliseconds, this.self, "good")
case other => println(s"$sender $other")
}
}
哪个会产生:
Actor[akka://Test/deadLetters] bad
Actor[akka://Test/user/test-actor#621986067] good
推荐答案
这是由于import context._
调用引起的.这条线在解决scheduleOnce()
函数获取发送者所需的implicit ActorRef
方面造成了歧义.
This happened because of the import context._
call. This line is causing an ambiguity in resolving the implicit ActorRef
required by the scheduleOnce()
function to get the sender.
ActorRef
self
存在两次-一次出现在Actor
中(通常如此),一次出现在功能范围中(来自context
的import
).这会导致隐式找不到self
,并且由于tell()
默认为DeadLetters
,因此会导致您遇到问题.
The ActorRef
self
exists twice - once in the Actor
(as it normally is), and once in the function scope, from the import
from context
. This results in the implicit not finding self
, and as tell()
defaults to DeadLetters
, this results in the problem you have.
如果您注意到 import context._
的示例用法在Akka文档中,它是在实例级别而非功能级别完成的.这意味着self
将替换Actor
的默认值,而不是对其进行阴影处理,从而消除歧义.
If you note the example usage of import context._
in the Akka docs, it is done at instance-level, not function level. This means self
replaces the Actor
's default value instead of shadowing it, removing the ambiguity.
其他选项是仅导入context.dispatcher
以使scheduleOnce()
调用正常工作,或显式传递它.
Other options are to import only context.dispatcher
to make the scheduleOnce()
call work, or pass it explicitly.
import context._ // Option 1
override def receive = {
case Worked => ???
case DidNotWork =>
val target = sender() // Avoid closing over sender().
//import context.dispatcher // Option 2
context.system.scheduler.scheduleOnce(500.milliseconds, target, TryAgain)
//context.system.scheduler.scheduleOnce(500.milliseconds, target, TryAgain)(context.dispatcher) // Option 3
}
这篇关于为什么我的sender()DeadLetters来自计划的邮件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!