10月16日星期三更新)今天有一个PullRequest,提供有关超时的目标信息。 https://github.com/akka/akka/pull/1780
Akka的超时异常非常无益。
是否有某种方法可以获得关于超时中发生的位置/内容的有用信息?
这样的例外没有帮助
java.util.concurrent.TimeoutException: Futures timed out after [5000] milliseconds
at akka.dispatch.DefaultPromise.ready(Future.scala:834)
at akka.dispatch.DefaultPromise.ready(Future.scala:811)
at akka.dispatch.Await$.ready(Future.scala:64)
at nl.cwi.crisp.examples.p2p.scala.Network.<init>(Node.scala:136)
at nl.cwi.crisp.examples.p2p.scala.Main$$anonfun$11.apply(Node.scala:164)
at nl.cwi.crisp.examples.p2p.scala.Main$$anonfun$11.apply(Node.scala:164)
at akka.actor.ActorCell.newActor(ActorCell.scala:488)
at akka.actor.ActorCell.create$1(ActorCell.scala:506)
at akka.actor.ActorCell.systemInvoke(ActorCell.scala:591)
at akka.dispatch.Mailbox.processAllSystemMessages(Mailbox.scala:191)
at akka.dispatch.Mailbox.run(Mailbox.scala:160)
at akka.dispatch.ForkJoinExecutorConfigurator$MailboxExecutionTask.exec(AbstractDispatcher.scala:505)
at akka.jsr166y.ForkJoinTask.doExec(ForkJoinTask.java:259)
at akka.jsr166y.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:997)
at akka.jsr166y.ForkJoinPool.runWorker(ForkJoinPool.java:1495)
at akka.jsr166y.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104)
答案 0 :(得分:3)
以目前的方式使用akka代码,它不会发生。让我们先来看一看为什么。如果您查看PromiseActorRef
对象,您可以看到:
def apply(provider: ActorRefProvider, timeout: Timeout): PromiseActorRef = {
val result = Promise[Any]()
val scheduler = provider.guardian.underlying.system.scheduler
val a = new PromiseActorRef(provider, result)
implicit val ec = a.internalCallingThreadExecutionContext
val f = scheduler.scheduleOnce(timeout.duration) { result tryComplete Failure(new AskTimeoutException("Timed out")) }
result.future onComplete { _ ‚áí try a.stop() finally f.cancel() }
a
}
这是调度并行(与实际actor调用并行)超时的位置。这个类没有关于它发送什么消息的内容,也没有它发送给它的actor参考的上下文。这可能就是为什么它只是说“Timed Out”并不是很有用。我有点希望那些类型安全的人稍微调整一下以提供更多信息,但是如果他们不这样做或者你想要过时的东西,你可以尝试这样的事情:
object NewAskPattern{
implicit def ask(ref:ActorRef) = new BetterTimeoutMessageSupportAskableRef(ref)
}
class BetterTimeoutMessageSupportAskableRef(ref: ActorRef) {
import akka.pattern.AskableActorRef
val askRef = new AskableActorRef(ref)
def ask(message: Any)(implicit timeout: Timeout, ec:ExecutionContext): Future[Any] =
(askRef ? message) recover{
case to:TimeoutException =>
val recip = askRef.actorRef.path
val dur = timeout.duration
throw new TimeoutException(s"Timed out sending message $message to recipient $recip using timeout of $dur")
}
def ?(message: Any)(implicit timeout: Timeout, ec:ExecutionContext): Future[Any] =
ask(message)(timeout, ec)
}
class MySlowActor extends Actor{
def receive = {
case any =>
Thread.sleep(5000)
sender ! "bar"
}
}
object NewMessageTest{
import NewAskPattern.ask
def main(args: Array[String]) {
implicit val timeout = Timeout(2 seconds)
val sys = ActorSystem()
import sys.dispatcher
val slow = sys.actorOf(Props[MySlowActor])
val fut = slow ? "foo"
fut onComplete (println(_))
}
}
这里的一般想法是从Akka lib中包装AskableActorRef
并稍微增强它。我正在使用Future
返回的ask
并添加recover
组合器,以便在我们超时时调整消息。由于此类具有发送消息的内容以及发送给谁的内容,因此可以制定更有用的消息。然后NewAskPattern
对象包含新的隐式对象,为您提供允许您获得此增强行为的BetterTimeoutMessageSupportAskableRef
。这是一个完美的解决方案?可能不是,但如果你真的想要这种行为,它可能是一个很好的起点。