我目前正在使用Rhino在一个宁静的服务中评估javascript脚本。我希望有一个评估时间。 我创建了一个模拟示例actor(使用scala 2.10 akka actors)。
case class Evaluate(expression: String)
class RhinoActor extends Actor {
override def preStart() = { println("Start context'"); super.preStart()}
def receive = {
case Evaluate(expression) ⇒ {
Thread.sleep(100)
sender ! "complete"
}
}
override def postStop() = { println("Stop context'"); super.postStop()}
}
现在我按如下方式运行这个演员:
def run {
val t = System.currentTimeMillis()
val system = ActorSystem("MySystem")
val actor = system.actorOf(Props[RhinoActor])
implicit val timeout = Timeout(50 milliseconds)
val future = (actor ? Evaluate("10 + 50")).mapTo[String]
val result = Try(Await.result(future, Duration.Inf))
println(System.currentTimeMillis() - t)
println(result)
actor ! PoisonPill
system.shutdown()
}
在这样的闭包中使用ActorSystem是否明智?它可能同时有请求?
我是否应该将ActorSystem设为全局,并且在这种情况下是否可以?
是否有更合适的替代方法?
编辑:我想我需要直接使用期货,但我需要preStart和postStop。目前正在调查中。 编辑:似乎你没有得到与期货挂钩。答案 0 :(得分:2)
我会尽力回答你的一些问题。
首先,ActorSystem
是一个非常重的构造。您不应该为每个需要actor的请求创建一个。您应该全局创建一个,然后使用该单个实例来生成您的actor(并且system.shutdown()
中不再需要run
)。我相信这涵盖了你的前两个问题。
在这里使用actor执行javascript的方法对我来说似乎很有道理。但是,您可能希望在RhinoActor
后面聚集一堆Router
s而不是为每个请求启动一个actor,每个实例都有自己的rhino引擎,该引擎将在{{1}期间设置}。这样做将消除每个请求的rhino初始化成本,从而加快您的js评估速度。只需确保适当调整池的大小。此外,如果采用这种方法,则无需为每个请求发送preStart
条消息。
您还可能希望查看非阻止回调PoisonPill
,onComplete
和onSuccess
,而不是使用阻止onFailure
。这些回调也尊重超时,并且优于阻止更高的吞吐量。只要上行等待这种响应的方式可以处理异步性(即具有异步能力的Web请求),那么我建议走这条路。
要记住的最后一件事是,即使代码将在超时后返回调用者,如果actor尚未响应,则actor仍然继续处理该消息(执行评估)。它不会因为调用者超时而停止并移动到下一条消息。只是想明确表示不是。
修改强>
在回应你关于停止长时间执行的评论时,有一些与Akka有关的事情要先考虑。您可以调用停止actor,发送Await
或Kill
,但如果处理它当前正在处理的消息,则这些都不会停止。它们只是阻止它接收新消息。在你的情况下,使用Rhino,如果有可能进行无限的脚本执行,那么我建议在Rhino中处理这个问题。我会深入研究这篇文章(Stopping the Rhino Engine in middle of execution)的答案,并在演员中设置你的Rhino引擎,如果它已经执行了太长时间它会自动停止。该失败将发送给主管(如果池化)并导致重新启动池化实例,这将在PosionPill
中初始化新的Rhino。这可能是处理长时间运行脚本的最佳方法。