Akka 演员总是超时等待未来
Akka actors always times out waiting for future
我有下面定义的以下演员,意在 "login" 一个用户。
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
returns一个Future[Option[User]]
下面是非常简单的 API 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")
}
}
}
两个 println
调用都会执行,但是 login
调用总是会失败,表示请求已超时。有什么建议吗?
当你做这样的事情时(在 Future
s 回调中访问发件人)你需要在收到请求时将 sender
存储在外部范围的 val
中,因为它很可能在 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
}
}
我有下面定义的以下演员,意在 "login" 一个用户。
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
returns一个Future[Option[User]]
下面是非常简单的 API 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")
}
}
}
两个 println
调用都会执行,但是 login
调用总是会失败,表示请求已超时。有什么建议吗?
当你做这样的事情时(在 Future
s 回调中访问发件人)你需要在收到请求时将 sender
存储在外部范围的 val
中,因为它很可能在 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
}
}