3

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)
4

1 に答える 1

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
}

これは、並列 (実際のアクター呼び出しと並列) タイムアウトがスケジュールされる場所です。このクラスには、送信しているメッセージや送信先のアクター ref に関するコンテキストはありません。それがおそらく、あまり役に立たない「タイムアウト」と表示される理由です。タイプセーフな人たちがこれを少し調整してより多くの情報を提供してくれることを期待していますが、そうでない場合、または暫定的に何かが必要な場合は、次のようなことを試すことができます。

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(_))
  }
}

ここでの一般的な考え方はAskableActorRef、Akka lib から をラップして、少し強化することです。Future返された byを受け取り、それにコンビネータをask追加して、recoverタイムアウトになったときにメッセージを微調整できるようにします。このクラスには、送信されたメッセージと送信先のコンテキストがあるため、より役立つメッセージを作成できます。次に、オブジェクトには、この強化された動作を取得できるようにするNewAskPatternための新しい暗黙的なものが含まれています。BetterTimeoutMessageSupportAskableRefこれは完璧な解決策ですか?おそらくそうではありませんが、この動作が本当に必要な場合は、良い出発点になる可能性があります。

于 2013-08-16T12:13:53.173 に答える