2012-08-23 12 views
5

Uso akka por algún tiempo. Empecé a ver algunos patrones en mi código para resolver la respuesta tardía para async io. ¿Está bien esta implementación? ¿Hay otra forma de hacer una respuesta tardía sin bloque?Última respuesta de async io en Akka

class ApplicationApi(asyncIo : ActorRef) extends Actor { 
    // store senders to late reply 
    val waiting = Map[request, ActorRef]() 

    def receive = { 
     // an actore request for a user, store it to late reply and ask for asyncIo actor to do the real job 
     case request : GetUser => 
      waiting += (sender -> request) 
      asyncIo ! AsyncGet("http://app/user/" + request.userId) 
     // asyncio response, parse and reply 
     case response : AsyncResponse => 
      val user = parseUser(response.body) 
      waiting.remove(response.request) match { 
       case Some(actor) => actor ! GetUserResponse(user) 
      } 
    } 
} 

Respuesta

5

Una forma de evitar el bloqueo a la espera de una respuesta es enviar utilizando el método de ask a.k.a. ? operador-que devuelve Future (a diferencia de ! que devuelve ()).

Usando los métodos onSuccess o foreach, puede especificar las acciones que se realizarán si/cuando el futuro se completa con una respuesta. Para utilizar esta lo que necesita para mezclar en el AskSupport rasgo:

class ApplicationApi(asyncIo : ActorRef) extends Actor with AskSupport { 

    def receive = { 
    case request: GetUser => 
     val replyTo = sender 
     asyncIo ? AsyncGet("http://app/user/" + request.userId) onSuccess { 
     case response: AsyncResponse => 
      val user = parseUser(response.body) 
      replyTo ! GetUserResponse(user) 
     } 

} 

Evitar el uso de esta técnica para llevar a cabo cualquier efecto secundario que modifica el estado de la ApplicationApi actor, ya que el efecto va a pasar fuera de sincronía con el recibir lazo. Sin embargo, reenviar mensajes a otros actores debería ser seguro.


Por cierto, aquí hay un truco para capturar la corriente sender como parte de la coincidencia de patrones, evitando la necesidad de asignar a una variable más tarde.

trait FromSupport { this: Actor => 
    case object from { 
    def unapply(msg: Any) = Some(msg, sender) 
    } 
} 

class MyActor extends Actor with FromSupport { 
    def receive = { 
    case (request: GetUser) from sender => 
     // sender is now a variable (shadowing the method) that is safe to use in a closure 
    } 
} 
+1

Creo que tiene razón; Olvidé que 'sender' es una propiedad mutable del Actor y no solo una variable que se puede cerrar. –

+2

ese extractor de infijo es realmente interesante – sourcedelica