scala - 使用 Guice 注入(inject) Akka Actor 来玩 Framework 2.5 失败

标签 scala dependency-injection akka playframework-2.5

我正在尝试在 Play 2.5 应用程序中使用 Akka actor 进行依赖注入(inject)。我基本上就跟着the documentation on that ,这是我的代码的一瞥:

Actor

基本上,我有一个简单的参与者,它接收一些数据,处理它,然后将其发送回调用者。

package actors    

import akka.actor._
import akka.pattern.{AskTimeoutException, ask}
import akka.util.Timeout
import javax.inject._

import com.google.inject.assistedinject.Assisted
import play.api.Configuration

import scala.concurrent.duration._
import scala.concurrent.ExecutionContext
import scala.concurrent.Future

object ServiceActor {
  val ConfigKey = "actors.path" // remote actor path

  trait Factory {
    def apply(key: String): Actor
  }
}

class ServiceActor @Inject()(configuration: Configuration,
                                   actorSystem: ActorSystem,
                                   @Assisted key: String)
                                  (implicit val ec: ExecutionContext)
  extends Actor {
  import ServiceActor._

  implicit val timeout = Timeout(5.minutes)

  def receive = {
    case data: SomeData => sender ! someFunction(data)
  }

  // implemented in the real code, omitted because not important for the question
  def someFunction = ??? 
}

模块

根据文档,我需要制作一个简单的模块并激活它。这是该模块:

package modules

import com.google.inject.AbstractModule
import play.api.libs.concurrent.AkkaGuiceSupport

import actors.ServiceActor

class ServiceModule extends AbstractModule with AkkaGuiceSupport {
  def configure = {
    bindActor[ServiceActor]("service-actor")
  }
}

然后我通过将以下行添加到 application.conf 来激活此模块:

play.modules {
  enabled += modules.ServiceModule
}

Controller

最后,我尝试在 Controller 中使用 actor:

package controllers

import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import javax.inject._

import play.api.mvc._

import scala.concurrent.duration._
import scala.concurrent.ExecutionContext

@Singleton
class SearchController @Inject()(@Named("service-actor") serviceActor: ActorRef)
                                (implicit ec: ExecutionContext)
  extends Controller {

  implicit val timeout = Timeout(5.minutes)

  def search(param: String) = Action.async {

    val request = SomeRequestType(param)

    (serviceActor ? request).mapTo[SomeResponseType] map { result =>
      Ok(result.toString)
    }
  }
}

据我所知,我完全遵循了文档,但是调用 Controller 给了我这个错误:

[AskTimeoutException: Recipient[Actor[akka://application/user/service-actor#-366470383]] 
had already been terminated. 
Sender[null] sent the message of type "some.namespace.SomeRequestType".]

据我所知,错误是关于 actor 是一个 null,我们无法向它发送消息。虽然错误代码显示“已被终止”,但看起来 Actor 从一开始就从未被启动过。

我不知道该先看哪里,也不知道我做错了什么,因为我没有使用 Guice 的经验。

问题是,我做错了什么?为什么 Actor 没有启动,或者如果它确实已经终止,为什么会终止?我该如何解决这个问题?

非常感谢。

最佳答案

希望您已经解决了这个问题。不过我还是把答案贴在这里,仅供一些新人引用,因为我花了一段时间才弄清楚这个问题的原因。

As far as I can understand, the error is about how the actor is a null, and we can't send message to it.

不完全是。问图案?有一个隐式参数sender,默认为ActorRef.noSender,源码为here

通常情况下,如果您位于 Actor 内,则在作用域中会有一个名为 self 的隐式 ActorRef,但由于您不在 Actor 内,因此仅采用默认值。

While the error code said "had already been terminated", it looks like the actor's never been initiated in the first place.

正确。很可能你的 Actor 一开始就没有正确启动。在您的控制台中,您应该会看到比从 Play 网页的响应中看到的错误消息更多的错误消息。

例如,下面是我在收到 AskTimeoutException 之前实际遇到的错误。

1 error
akka.actor.ActorInitializationException: akka://application/user/user-actor: exception during creation
    at akka.actor.ActorInitializationException$.apply(Actor.scala:193)
    at akka.actor.ActorCell.create(ActorCell.scala:608)
    at akka.actor.ActorCell.invokeAll$1(ActorCell.scala:462)
    at akka.actor.ActorCell.systemInvoke(ActorCell.scala:484)
    at akka.dispatch.Mailbox.processAllSystemMessages(Mailbox.scala:282)
    at akka.dispatch.Mailbox.run(Mailbox.scala:223)
    at akka.dispatch.Mailbox.exec(Mailbox.scala:234)
    at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at akka.dispatch.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
Caused by: com.google.inject.ConfigurationException: Guice configuration errors:

最后,您可能需要再次检查 sbt 控制台以及您的注入(inject),以确保 actor 一开始就已启动。

关于scala - 使用 Guice 注入(inject) Akka Actor 来玩 Framework 2.5 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37178675/

相关文章:

scala - 'classOf' 表达式如何在 scala AST 中表示

scala - 如何使用 sbt 和 onejar 插件添加 log4J 属性文件?

JavaFX 应用程序线程 - 使用 Gluon Ignite 依赖注入(inject)时

java - 使用 ThreadLocals 的 Akka 和 Java 库

Scala Nil 等效于 Set

scala - 光滑的过滤器或不再支持逻辑操作的地方?

c# - 与生产者基于注解的 DI

c# - 我应该使用 Unity(它还活着吗)?

scala - AKKA HTTP 源流与 Futures

java - Akka Actor 意外地清理了它的状态