为什么我的sender()DeadLetters来自计划的邮件? [英] Why is my sender() DeadLetters from a scheduled message?

查看:92
本文介绍了为什么我的sender()DeadLetters来自计划的邮件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试安排一段时间后要发送的消息-简单的重试.

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中(通常如此),一次出现在功能范围中(来自contextimport).这会导致隐式找不到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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆