2012-04-04 13 views
2

私はAkkaを使用して、カスタムアプリケーションプロトコル用のTCPサーバーを実装しようとしています。私はここに与えられた例に従うことを試みています:http://doc.akka.io/docs/akka/2.0/scala/io.html for ...ブロック内の非ブロックIOを行うにはyieldループを使います。Scala + Akkaによる奇妙な試行錯誤の動作

私がyieldブロックの内側から例外をスローすると、ブロックの外側からそれをキャッチできないことがわかりました。私は、AkkaやScalaがここでどのように働いているのかについて基本的な誤解があると思っています。

私はこれまでコード煮詰めました:ここに要旨に従って

import akka.actor._ 
import java.net.InetSocketAddress 

class EchoServer(port: Int) extends Actor { 

    val state = IO.IterateeRef.Map.async[IO.Handle]()(context.dispatcher) 

    override def preStart { 
    IOManager(context.system) listen new InetSocketAddress(port) 
    } 

    def receive = { 
    case IO.NewClient(server) => 
     val socket = server.accept() 
     state(socket) flatMap (_ => EchoServer.processRequest(socket)) 
    case IO.Read(socket, bytes) => 
     state(socket)(IO.Chunk(bytes)) 
    case IO.Closed(socket, cause) => 
     state(socket)(IO.EOF(None)) 
     state -= socket 
    } 
} 

object EchoServer extends App 
{ 
    def processRequest(socket: IO.SocketHandle): IO.Iteratee[Unit] = 
    { 
    println("In process request") 
    try { 
     for { 
     bs <- IO take 1 
     } yield { 
     println("I'll get here") 
     throw new Exception("Hey-o!") 
     println("But not here ... as expected") 
     } 
    } catch { 
     case e: Exception => println("And not here ... wtf?"); IO.Done() // NEVER GETS HERE 
    } 
    } 

    ActorSystem().actorOf(Props(new EchoServer(8080))) 
} 

たぶんもっと便利に:https://gist.github.com/2296554

を制御は、このような状況で私のcatchブロックに到達していない理由を誰も説明できますか?

私はアッカにデバッグログをオンにした場合、私は出力にこのメッセージが表示されていることに気づい:

[DEBUG] [04/03/2012 22:42:25.106] [EchoServerActorSystem-akka.actor.default-dispatcher-1] [Future] Hey-o! 

だから私は例外がアッカディスパッチャによって処理なっていると思いますか?どのようにそれが可能か誰でも説明できますか?

答えて

6

ノンブロッキングIOのポイントは、いつどこで実行されるか保証されないことです。覚えておいてください。

(IO take 1).map(bs => { 
    println("I'll get here"); throw // ... 
} 

このコードは何をしていますか? IO take 1は、いくつかのノンブロッキングFutureのようなものを返し、mapメソッドを使って変換関数を追加します。私。 IO take 1がいつでも(そしてどこにでも)いつでも、結果にmapが適用されます。

これのすべては、いくつかの他のスレッド(または非ブロッキングのセマンティクスを実装する他の方法を使用して)で起こるので、try方法はありません - スローされる任意Exception Sに反応するcatchは。 bs => println(…) …メソッドも例外処理を知らないでしょう。すべての入力はbsの入力を変換し、終了時に結果を得なければならないことをすべて知っています。

学習するレッスン:非ブロッキングコードを使用すると副作用を回避できます。特に、実行の流れを変更するために副作用が使用されている場合。実際に例外をキャッチするためには、私が(未テスト; APIを参照)、以下のようにあなたがそれを構築する必要があります考えて

:非常に役立つ応答のための

def processRequest(socket: IO.SocketHandle): IO.Iteratee[Unit] = 
    { 
    println("In process request") 
    (
     for { 
     bs <- IO take 1 
     } yield { 
     println("I'll get here") 
     throw new Exception("Hey-o!") 
     println("But not here ... as expected") 
     } 
    ) recover { 
     case e: Exception => println("And here ...?"); IO.Done() 
    } 
    } 
+0

おかげで、それは本当に物事をクリアします。 –