2016-03-25 4 views
0

У меня есть следующий актер, как определено ниже, для «входа» пользователя.Акка акка всегда в ожидании будущего

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

Примечание: userService.getUserById возвращает Future[Option[User]]

И следующую очень упрощенно API кал к нему

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

Оба println вызовов будут выполняться, но login вызова будет всегда терпит неудачу говорит, что спросить, есть тайм-аут. Какие-либо предложения?

+0

не следует использовать pipeTo I/O МАПТО? – Ashalynd

ответ

3

Когда вы делаете такую ​​вещь (доступ к отправителю в Future сек обратного вызова), вы должны хранить sender в val в Outter объеме при получении запроса, потому что это очень вероятно, изменится до Future завершается.

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

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

Вы также никогда не отправляете результат, когда пользователь не был найден.

Что вы на самом деле должны делать здесь труба Future результат к 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 
    } 
} 

или с принтами

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

В вашем первом примере я думаю, что 'val recipient = sender' должен быть' val recipient = sender() '(обратите внимание на круглые скобки). – russianmario

+0

Scala позволяет опустить скобки для методов 0-arity, см .: http://docs.scala-lang.org/style/method-invocation.html –

+0

Мои извинения - я мог бы поклясться, что я просто где-то читал, что это было плохо (или даже неправильно), но я больше не могу найти ссылку. Должно быть, неправильно. – russianmario

Смежные вопросы