2012-04-04 2 views
2

Akka를 사용하여 사용자 지정 응용 프로그램 프로토콜 용 TCP 서버를 구현하려고합니다. 여기에 주어진 예제를 따르려고 노력하고있어 : http://doc.akka.io/docs/akka/2.0/scala/io.html for ... 비상용 IO를 for ... yield 루프 내에서 수행하려고한다.Scala + Akka로 이상한 try/catch 동작

yield 블록 내부에서 예외를 throw하면 블록 외부에서 예외를 catch 할 수 없습니다. 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))) 
} 

여기에 요점 따르 어쩌면 더 편리 : 컨트롤이 상황에서 내 catch 블록에 도달하지 않는 이유 https://gist.github.com/2296554

아무도 설명 할 수 있습니까?

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

그래서 나는 예외가 Akka 디스패처에 의해 처리지고 같아요

은 내가 Akka에서 디버그 로깅을 설정하는 경우, 내가 출력에이 메시지가 표시 것으로 나타났습니다? 아무도 그것이 가능한 방법을 설명 할 수 있습니까?

답변

6

논 블로킹 IO의 요점은 물론 그것이 언제 어디서 실행되는지 보장 할 수 없다는 것입니다. 그 중 하나는 이해를 위해 쓸 수 있음을 기억하십시오.

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

이 코드는 어떤 기능을 수행합니까? IO take 1Future과 같은 것이 아닌 일부 비 차단을 반환하고 map 메서드를 통해 변환 함수를 추가합니다. 나는. IO take 1이 준비되면 언제든지 결과에 map이 적용됩니다.

이 모든 다른 스레드 (또는 비 블로킹 의미를 구현하는 다른 방법을 사용하여)에서 발생하기 때문에 try 방법이 없습니다 - 슬로우 어떤 Exception들에 반응하는 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

감사합니다, 정말 물건을 지 웁니다. –