2012-08-23 2 views
5

J'utilise akka depuis quelque temps. J'ai commencé à voir des modèles dans mon code pour résoudre la réponse tardive pour async io. Cette implémentation est-elle correcte? Il y a une autre façon de faire une réponse tardive sans blocage?Réponse tardive d'async io dans 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) 
      } 
    } 
} 

Répondre

5

Une façon d'éviter de bloquer en attendant une réponse consiste à envoyer en utilisant la méthode a.k.a ask. ? opérateur-qui renvoie un Future (contrairement à ! qui renvoie ()). En utilisant les méthodes onSuccess ou foreach, vous pouvez spécifier les actions à effectuer si/quand le futur est complété par une réponse. Pour utiliser cela, vous devez mélanger dans le trait AskSupport:

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

} 

Évitez d'utiliser cette technique pour réaliser un effet secondaire qui modifie l'état de l'acteur ApplicationApi, parce que l'effet va se passer hors de synchronisation avec la réception boucle. Transférer des messages à d'autres acteurs devrait être sûr, cependant.


Soit dit en passant, est une astuce ici pour capturer la sender actuelle dans le cadre du match de modèle, ce qui évite la nécessité d'assigner à une variable plus tard.

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

Je pense que vous avez raison; J'ai oublié que 'sender' est une propriété mutable de l'acteur et pas seulement une variable qui peut être fermée. –

+2

que l'extracteur infixe est vraiment intéressant – sourcedelica