Akka Ask模式的Timeout阻止代码执行

时间:2015-01-02 17:46:02

标签: scala parallel-processing akka

我刚开始学习Scala的Akka库。我遇到了使用Ask模式从Actor获取响应(就像启动一个线程来完成一些计算并获得结果)。

下面是我的代码,其中我使用了Ask模式,其中Timeout阻止它执行。为什么呢?

import akka.actor._
import akka.routing._
import akka.util.Timeout
import akka.pattern.ask
import java.math.BigInteger
import java.time.LocalDate
import scala.concurrent.duration._
import scala.concurrent.Await
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global 
import scala.util.{Success, Failure}


object Main extends App {

  val system = ActorSystem("listRetriever")
  val workerActor = system.actorOf(Props[Worker], "workerActor")
  val listRetriever= new listRetriever
  implicit val timeout = Timeout(10 seconds)

  val future = workerActor ? new Work(date, listRetriever)

  future onComplete {
    case Success(result: Result) => println(result.getList())
    case Failure(result) => println(result)
  }

  system.shutdown
}

2 个答案:

答案 0 :(得分:6)

如果您查看Timeout课程的定义,您会发现它需要FiniteDuration

case class Timeout(duration: FiniteDuration) extends Product with Serializable

http://doc.akka.io/api/akka/current/#akka.util.Timeout

这是故意的,因此ask特别不会永远运行。

所以不,你不能在没有有限超时的情况下使用ask

答案 1 :(得分:1)

警告,这是一种黑客行为:
这可能不是“最佳实践”,但它是一种有效的方法/解决方法,可以获得无超时“问”。

如果您的原始Work消息定义如下:

case class Work(params: Params)

然后将Promise添加到该案例类中,即

case class Work(params: Params, completionPromise: Promise[Result])

创建一种方便的方法,根据Params

处理创建和发送该消息的方法
def doWork(params: Params): Future[Result] = {
  val completionPromise = Promise[Result]
  val msg = Work(params, completionPromise)
  workerActor ! msg
  completionPromise.future
}

这仅适用于 IF workerActor实现知道如何处理completionPromise。如果工作人员实施不在您的控制之下,则无法执行此操作。

此外,您必须确保worker actor将异常传递给promise。否则,你最终会得到一个永远不会完成的未来。例如,这很糟糕:

def receive = {
  case Work(params, completionPromise) =>
    val result = doErrorProneOperation(params)

    // if an exception is thrown, the following will never happen
    completionPromise success result
}

您必须确保考虑例外情况,否则其他内容会显示为挂起:

def receive = {
  case Work(params, completionPromise) =>
    val result = Try { doErrorProneOperation(params) }
    completionPromise complete result
}

请参阅the docs for Promise