注入Akka Actor以使用Guice播放Framework 2.5失败

时间:2016-05-12 06:16:30

标签: scala dependency-injection akka playframework-2.5

我试图在我的Play 2.5应用程序中使用依赖注入的Akka actor。我基本上遵循了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
}

控制器

最后,我尝试在控制器中使用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)
    }
  }
}

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

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

据我所知,错误是关于演员是null的方式,我们无法向其发送消息。虽然错误代码表示"已经被终止",但看起来这个演员从未被首发过。

我不确定首先要去哪里,因为我没有使用过Guice的经验,所以我做错了什么。

问题是,我做错了什么?为什么没有发起演员,或者如果它确实已经被终止,为什么它被终止?我该如何解决这个问题?

非常感谢。

1 个答案:

答案 0 :(得分:0)

希望你已经解决了这个问题。但是我仍然在这里发布答案仅仅是为了一些新来者的参考,因为我花了一段时间来弄清楚这个问题的原因。

  

据我所知,错误是关于actor如何为null,我们无法向其发送消息。

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

通常情况下,如果你在一个Actor中,你在一个名为self的范围内有一个隐含的ActorRef,但由于你不在一个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控制台以及注入,以确保首先启动了演员。