Используйте будущее в Spray Routing
Я новичок в асинхронном программировании. Я прочитал этот учебник http://danielwestheide.com/blog/2013/01/09/the-neophytes-guide-to-scala-part-8-welcome-to-the-future.html и был удивлен тем, насколько легко я может включить будущее в программу. Однако когда я использовал Future with Routing, тип возвращаемого значения был неправильным.
get {
optionalCookie("commToken") {
case Some(commCookie) =>
val response = (MTurkerProgressActor ? Register).mapTo[..].map({...})
val result = Await.result(response, 5 seconds)
setCookie(HttpCookie("commToken", content = result._2.mturker.get.commToken)) {
complete(result._1, result._2.mturker.get)
}
case None => // ...
}
}
Я действительно не хочу использовать Await
(какой смысл асинхронного, если я просто блокирую поток и жду 5 секунд?). Я пытался использовать for
-понимание или flatMap
и поместите setCookie
а также complete
действия внутри, но возвращаемый тип недопустим для Spray. Для понимания возвращается "Единица", и flatMap
возвращает будущее.
Так как мне нужно настроить этот файл cookie, мне нужны данные внутри. Является Await
решение? Или есть более умный способ?
2 ответа
Вы можете использовать onSuccess
директива:
get {
optionalCookie("commToken") { cookie =>
//....
val response = (MTurkerProgressActor ? Register).mapTo[..].map({...})
onSuccess(response) {
case (result, mTurkerResponse) =>
setCookie(HttpCookie("commToken", content = mTurkerResponse.mturker.get.commToken)) {
complete(result, mturkerResponse.mturker.get)
}
}
}
Есть также onFailure
а также onComplete
(для которого вы должны соответствовать на Success
а также Failure
) См. http://spray.io/documentation/1.2.1/spray-routing/future-directives/onComplete/
Кроме того, вместо использования get
напрямую это гораздо более идиоматично в использовании map
(Я предполагаю, что mturker
является Option
или что-то подобное)
case (result, mTurkerResponse) =>
mTurkerResponse.mturker.map { mt =>
setCookie(HttpCookie("commToken", content = mt.commToken)) {
complete(result, mt)
}
}
Вы также можете сделать пользовательскую директиву, используя этот код -
case class ExceptionRejection(ex: Throwable) extends Rejection
protected def futureDirective[T](x: Future[T],
exceptionHandler: (Throwable) => Rejection = ExceptionRejection(_)) =
new Directive1[T] {
override def happly(f: (::[T, HNil]) => Route): Route = { ctx =>
x
.map(t => f(t :: HNil)(ctx))
.onFailure { case ex: Exception =>
ctx.reject(exceptionHandler(ex))
}
}
}
Пример использования -
protected def getLogin(account: Account) = futureDirective(
logins.findById(account.id)
)
getAccount(access_token) { account =>
getLogin(account) { login =>
// ...
}
}