我是异步编程的新手。我阅读了这篇教程http://danielwestheide.com/blog/2013/01/09/the-neophytes-guide-to-scala-part-8-welcome-to-the-future.html,并对我将Future融入该计划毫不费力感到惊讶。但是,当我使用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是不可接受的。 for-comprehension返回" Unit"和flatMap
返回Future。
因为我需要设置这个cookie,所以我需要里面的数据。问题是Await
吗?或者有一种简单的方法吗?
答案 0 :(得分:15)
您可以使用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)
}
}
答案 1 :(得分:1)
您也可以使用此代码制作自定义指令 -
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 =>
// ...
}
}