我试图在我的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的经验,所以我做错了什么。
问题是,我做错了什么?为什么没有发起演员,或者如果它确实已经被终止,为什么它被终止?我该如何解决这个问题?
非常感谢。
答案 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控制台以及注入,以确保首先启动了演员。