我正在尝试安排在一段时间后发送的消息 - 简单的重试。
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
。为什么会这样?
(注意问题是另一个actor中的sender()
调用,它不在闭包中 - 这不是我关闭sender()
时的问题):
override def receive = {
case TryOnce => sender() ! DidNotWork
case TryAgain => sender() ! Worked // sender() here is DeadLetters!
}
完整示例(回复cmbaxter's comment):
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
答案 0 :(得分:2)
这是因为import context._
电话而发生的。此行导致解析implicit ActorRef
函数所需的scheduleOnce()
以获取发件人时出现歧义。
ActorRef
self
存在两次 - 一次在Actor
(通常是),一次在函数范围内,来自import
{{1} }}。这导致隐式找不到context
,而self
默认为tell()
,这会导致您遇到问题。
如果您注意the example usage of import context._
in the Akka docs,则会在实例级别而非功能级别完成。这意味着DeadLetters
会替换self
的默认值,而不是遮蔽它,从而消除歧义。
其他选项只能导入Actor
以使context.dispatcher
调用正常工作,或明确传递。
scheduleOnce()
答案 1 :(得分:0)
因此,在挖掘更多内容时,我同意导入context._
是问题所在。 self
上有ActorContext
,但不是隐含的。将其导入范围时,它会取代每个self
附带的隐式Actor
。所以现在你在范围内有一个self
参考,但它不再含蓄,这就是为什么你会看到一个死信。如果您将来遇到这样的情况,并且您想要完全导入上下文,因为您可以通过将调度移动到actor中的单独方法来轻松解决问题,如下所示:
class Test extends Actor {
override def receive = {
case "badtest" =>
import context._
scheduleFromMe("bad")
case "goodtest" =>
import context.dispatcher
scheduleFromMe("good")
case other => println(s"$sender $other")
}
def scheduleFromMe(s:String)(implicit ec:ExecutionContext) = context.system.scheduler.scheduleOnce(10.milliseconds, this.self, s)
}
从这个新方法的隐式参数中删除ActorRef
允许对调度程序的调用始终拾取作为此actor的隐式self ActorRef
。