2016-03-25 4 views
0

Ich habe den folgenden Akteur wie unten definiert, um einen Benutzer "einzuloggen".Akka Schauspieler warten immer auf die Zukunft

object AuthenticationActor { 
    def props = Props[AuthenticationActor] 

    case class LoginUser(id: UUID) 
} 

class AuthenticationActor @Inject()(cache: CacheApi, userService: UserService) extends Actor{ 
    import AuthenticationActor._ 

    def receive = { 
    case LoginEmployee(id: UUID) => { 
     userService.getUserById(id).foreach { 
     case Some(e) => { 
      println("Logged user in") 
      val sessionId = UUID.randomUUID() 
      cache.set(sessionId.toString, e) 
      sender() ! Some(e, sessionId) 
     } 
     case None => println("No user was found") 
     } 
    } 
    } 
} 

Hinweis: userService.getUserById gibt einen Future[Option[User]]

Und die folgende sehr einfache API, um es cal

class EmployeeController @Inject()(@Named("authentication-actor") authActor: ActorRef)(implicit ec: ExecutionContext) extends Controller { 

    override implicit val timeout: Timeout = 5.seconds 

    def login(id: UUID) = Action.async { implicit request => 
    (authActor ? LoginUser(id)).mapTo[Option[(User, UUID)]].map { 
     case Some(authInfo) => Ok("Authenticated").withSession(request.session + ("auth" -> authInfo._2.toString)) 
     case None => Forbidden("Not Authenticated") 
    } 
    } 
} 

Beide println Anrufe ausführen, aber login Anruf wird immer sagen, fail, dass die fragen hat Auszeit. Irgendwelche Vorschläge?

+0

sollten Sie nicht pipeTo verwenden i/o mapTo? – Ashalynd

Antwort

3

Wenn Sie so etwas tun (Sender innerhalb Future s Rückruf Zugriff) benötigen Sie sender in einem val in outter Umfang zu speichern, wenn Sie Anfrage erhalten, weil es sehr wahrscheinlich ändern, bevor Future abgeschlossen ist ist.

def receive = { 
    case LoginEmployee(id: UUID) => { 
     val recipient = sender 

     userService.getUserById(id).foreach { 
     case Some(e) => { 
      ... 
      recipient ! Some(e, sessionId) 
     } 
     ... 
     } 
    } 
    } 

Sie senden auch nie ein Ergebnis, wenn der Benutzer nicht gefunden wurde.

Was sollten Sie eigentlich hier tun, ist Rohr das Future Ergebnis an die sender

def receive = { 
    case LoginEmployee(id: UUID) => { 
    userService.getUserById(id) map { _.map { e => 
     val sessionId = UUID.randomUUID() 
     cache.set(sessionId.toString, e) 
     (e, sessionId) 
     } 
    } pipeTo sender 
    } 
} 

oder mit Prints

def receive = { 
    case LoginEmployee(id: UUID) => { 
    userService.getUserById(id) map { 
     case Some(e) => 
     println("logged user in") 
     val sessionId = UUID.randomUUID() 
     cache.set(sessionId.toString, e) 
     Some(e, sessionId) 
     case None => 
     println("user not found") 
     None 
    } pipeTo sender 
    } 
} 
+0

In Ihrem ersten Beispiel, ich denke, "val recipient = sender" sollte "val recipient = sender()" sein (beachten Sie die Klammern). – russianmario

+0

Scala erlaubt es, die Klammern für 0-Arity-Methoden wegzulassen, siehe: http://docs.scala-lang.org/style/method-invocation.html –

+0

Meine Entschuldigung - ich hätte schwören können, ich habe irgendwo gelesen, dass es schlecht ist üben (oder sogar falsch), dies zu tun, aber ich kann die Referenz nicht mehr finden. Muss falsch gelesen werden. – russianmario