Await.result on HttpService



我有一个带有http4s 0.15.16a和slick 3.2.1的scala项目,步骤如下:

  1. 通过休息呼叫接收 ID
  2. 将ID传递给MySlickDAO,该DAO以未来作为响应
  3. 调用 Await.result(res, Duration.Inf) on Future 由 MySlickDAO 返回
  4. 创建 JSON

问题是我使用Await.result,这是不好的做法 有更好的解决方案吗?

这里的代码:

val service = HttpService {
//http://localhost:8080/rest/id/9008E75A-F112-396B-E050-A8C08D26075F
case GET -> Root / "rest" / "id" / id =>
val res = MySlickDAO.load(id)
Await.result(res, Duration.Inf)
val ll = res.value.get.get
ll match {
case Failure(x) =>
InternalServerError(x)
case Success(record) =>
val r = record.map(x => MyEntity(x._1, x._2, x._3))
jsonOK(r.asJson)
}
case ....

}

您可以将一个Future的结果链接到另一个中,而不是等待:

val resFut = MySlickDAO.load(id)
resFut.map { record =>
val r = record.map(x => MyEntity(x._1, x._2, x._3))
jsonOK(r.asJson)
} recover { x =>
InternalServerError(x)
}

这样做的结果将是Future常见的超类型jsonOKInternalServerError(不熟悉你正在使用的库;所以我可能错误的加载类型:这不是一个Future[Try[_]]是吗?)。

顺便说一句:你的原始代码有一行非常有问题:

val ll = res.value.get.get

res.value是一个Option[Try[T]].在OptionTry上调用get通常是一个坏主意(即使在这种情况下由于AwaitOption永远不应该None,所以get在技术上是安全的),因为它可能会引发异常。你最好使用mapflatMap和朋友。

问题是http4s 0.15使用Scalaz并发结构,而Slick使用原生Scala并发结构,两者并非旨在相互协作。我的理解是,http4s 0.17+ 已经从 Scalaz 切换到 Cats,这可能需要使用原生的 Scala Futures,所以如果你能升级,那可能值得一试。如果没有,您可以通过手动创建一个包含您的未来的任务来处理转换:

def scalaFutureRes = MySlickDAO.load(id)
val scalazTaskRes = Task.async { register =>
scalaFutureRes.onComplete {
case Success(success) => register(success.right)
case Failure(ex)      => register(ex.left)
}
}

在这一点上,你得到了一个来自未来[结果类型]的任务[结果类型],你可以用你的其余逻辑映射/flatMap,就像Levi的答案一样。

你也可以为此使用 delorean 库,它通过隐式转换在有问题的类上定义了这个逻辑和相反的方向,这样你就可以在 Future 上调用 .toTask 以兼容的形式获取它。他们的自述文件也有很多关于转换和陷阱的有用信息。

最新更新