0

我目前正在使用 Rhino 在一个安静的服务中评估 javascript 脚本。我希望有一个评估超时。我创建了一个模拟示例演员(使用 scala 2.10 akka 演员)。

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。目前正在调查。编辑:似乎你没有得到期货的那些钩子。

4

1 回答 1

2

我会试着为你回答你的一些问题。

首先,anActorSystem是一个非常重的结构。您不应该为需要参与者的每个请求创建一个。您应该在全局范围内创建一个,然后使用该单个实例来生成您的演员(system.shutdown()在 中您将不再需要run)。我相信这涵盖了您的前两个问题。

您在这里使用演员执行 javascript 的方法对我来说似乎是合理的。但是,您可能希望RhinoActor在. 这样做将消除每个请求的犀牛初始化成本,加快你的 js 评估。只要确保你的游泳池大小合适。此外,如果您采用这种方法,则无需为每个请求发送消息。RouterpreStartPoisonPill

您可能还想查看非阻塞回调onCompleteonSuccessonFailure不是使用阻塞Await。这些回调也尊重超时,并且比阻塞更高的吞吐量更可取。只要上游等待此响应的任何方式都可以处理异步性(即支持异步的 Web 请求),那么我建议走这条路。

要记住的最后一件事是,即使如果参与者尚未响应,代码将在超时后返回给调用者,参与者仍会继续处理该消息(执行评估)。它不会仅仅因为呼叫者超时而停止并转到下一条消息。只是想澄清一下,以防万一。

编辑

在回应您关于停止长时间执行的评论时,首先要考虑一些与 Akka 相关的事情。您可以调用 stop 演员、发送 aKill或 a PosionPill,但如果处理当前正在处理的消息,这些都不会停止。他们只是阻止它接收新消息。在您的情况下,对于 Rhino,如果无限脚本执行是可能的,那么我建议在 Rhino 本身内处理这个问题。我将深入研究这篇文章的答案(在执行过程中停止 Rhino 引擎),并在 actor 中设置您的 Rhino 引擎,使其在执行时间过长时会自行停止。该失败将踢出到主管(如果池化)并导致该池化实例重新启动,这将在其中启动一个新的 RhinopreStart. 这可能是处理长时间运行脚本的可能性的最佳方法。

于 2013-07-11T13:16:55.837 回答