Akka - Sender [null]发送了类型的消息

时间:2016-05-25 13:43:02

标签: scala akka spray

我有一条喷射路线,我宣布我的一个演员。

val myActor = actorRefFactory.actorSelection("/user/my-actor")

我的路线如下:

get {
  path(Segment / Segment) { (poolId, trackId) =>
    respondWithMediaType(MediaTypes.`application/json`) {
      val request = Request(poolId, trackId)

      val f = (myActor ? request)
        .recoverWith {
          case a: AskTimeoutException =>
            Future.failed[StandardRoute](throw new Exception(s"We got a timeout", a))

          case e: Exception => Future.failed[StandardRoute](throw new Exception(s"We got an error", e))
        }

      onComplete(f) {
        case Success(resp) => complete(OK, resp)

        case Failure(e) =>
          log.error(s"Fatal request error: $trackId / $poolId", e)
          complete(InternalServerError, ErrorCodes.ErrorNotHandled)
      }
    }
  }
}

有时,我可以看到当我同时收到大量请求时,其中一些可能会因以下消息而失败:

  

引起:akka.pattern.AskTimeoutException:询问超时时间   [ActorSelection [Anchor(akka:// default /),Path(/ user / my-actor)]]之后   [8000毫秒]。 Sender [null]发送了类型的消息   “my.company.messages.Request”。

问题是,如果我采取相同的请求并尝试再次发送它,它可以工作,只有在有时会发生这种情况,我不知道如何解决这个问题。

演员确实做了很多事情,里面有很多未来,直到它给喷射路线返回一个值。

在actor中,我创建了一个名为replyTo的val,以保持发送者的值。

有关为什么有时会出现此错误的任何想法?

修改

仅举例说明我如何管理myActor:

class MyActor extends Actor with ActorLogging {

  private implicit val timeout = Timeout(8.seconds)

  def receive = {

    case req: Request =>

      val replyTo = sender()

      doOneThing.map { one =>

        doSecondThing(one).map { sec =>
          replyTo ! sec
        }
      }
  }
}

doOneThing和doSecondThing在哪里是期货......我有很多在不同情况下围绕这个演员传播。

3 个答案:

答案 0 :(得分:3)

您看到的发件人[null]是正常行为。 ask方法List<List<List<Double>>>采用隐式参数?,默认值为sender。通常情况下,如果您在ActorRef.noSender内,则在Actor范围内有一个隐式ActorRef,但由于您不在self,因此它只是采用默认值。

错误的原因可能是收到您的邮件的Actor没有及时响应。

答案 1 :(得分:0)

我认为你没有在这里使用路由,这就是你得到超时异常的原因。 例如, 假设您的一个请求需要1秒才能执行。 并且假设您一次收到4个请求,当请求到达一个actor时,它会附加到一个队列中,并且对于您等待8秒的每个请求。因此在队列中假设第4个请求将在4秒内执行,因此您将在8秒内获得响应。但是当一次发出100个请求并且你的一个actor可以处理它们时,并且对于第100个请求,它将花费100秒来执行但是你只等待第8个请求,这就是你获得超时的原因例外。

所以解决方法是,你可以在这里使用路由 - 例如 -

system.actorOf(RoundRobinPool(concurrency).props(Props(new MyActor())))

您可以在系统可用进程上设置并发性。假设如此设置并发值100,现在对于第100个请求,执行只需2秒。所以我认为路由可以是一个解决方案。

如果您不知道有多少请求可能是1k或更多,那么您可以动态创建actor,您可以根据请求动态创建actor。因此,无论何时请求到来,您的独立演员都将在那里为其提供服务。

答案 2 :(得分:0)

当我没有正确地将回复发送回发件人时,我会收到此类错误。

不正确(只返回值):

def receive = {
  case DataFetch =>
    data
}

更正(将值发送到sender):

  def receive = {
    case DataFetch =>
      sender ! data
  }