2012-08-23 21 views
5

Sto usando akka per un po 'di tempo. Ho iniziato a vedere alcuni modelli nel mio codice per risolvere la risposta tardiva per async io. Questa implementazione è ok? C'è un altro modo per fare una risposta in ritardo senza blocco?Risposta tardiva da async io in 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) 
      } 
    } 
} 

risposta

5

Un modo per evitare il blocco in attesa di una risposta è quello di inviare utilizzando il metodo di ask-a.k.a. Operatore ?, che restituisce un valore Future (a differenza di ! che restituisce ()).

Utilizzando i metodi onSuccess o foreach, è possibile specificare le azioni da eseguire se/quando il futuro viene completato con una risposta. Per utilizzare questo è necessario mescolare in AskSupport tratto:

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

} 

Evitare di utilizzare questa tecnica per eseguire qualsiasi effetto collaterale che modifica lo stato del ApplicationApi attore, perché l'effetto accadrà fuori sincronia con la ricezione ciclo continuo. Inoltrare messaggi ad altri attori dovrebbe essere sicuro, comunque.


proposito, qui è un trucco per catturare la corrente sender come parte del pattern match, evitando la necessità di assegnare ad una variabile successiva.

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

Penso che tu abbia ragione; Ho dimenticato che 'sender' è una proprietà mutabile dell'Actor e non solo una variabile che può essere chiusa. –

+2

che l'estrattore di infissi è davvero interessante – sourcedelica