0

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

  1. 通过 rest call 接收 ID
  2. 将 ID 传递给以 Future 响应的 MySlickDAO
  3. 在 MySlickDAO 返回的 Future 上调用 Await.result(res, Duration.Inf)
  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 ....

}

4

2 回答 2

1

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一个常见的超类型jsonOKand InternalServerError(不熟悉您正在使用的库;所以我可能有错误的加载类型:它不是 aFuture[Try[_]]是吗?)。

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

val ll = res.value.get.get

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

于 2017-09-19T19:17:32.607 回答
0

问题在于 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)
  }
}

此时,您已经从 Future[ResultType] 获得了一个 Task[ResultType],您可以将其与其他逻辑进行映射/flatMap,就像 Levi 的回答一样。

您还可以为此使用delorean库,该库通过隐式转换在相关类上定义了此逻辑和相反方向,因此您只需调用 Future 上的 .toTask 即可以兼容的形式获取它。他们的自述文件也有很多关于转换的有用信息以及存在的陷阱。

于 2017-11-17T16:19:00.703 回答