HttpService上的Await.result

时间:2017-09-19 17:39:55

标签: scala future slick-3.0 http4s http4s-circe

我使用http4s 0.15.16a和光滑的3.2.1进行scala项目,包括以下步骤:

  1. 通过休息电话
  2. 接收身份证
  3. 将ID传递给使用Future回复的MySlickDAO
  4. 在MySlickDAO返回的Future上调用Await.result(res,Duration.Inf)
  5. 创建json
  6. 问题是我使用了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 ....
    

    }

2 个答案:

答案 0 :(得分: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)
}

结果将是[{1}}和Future的常见超类型的jsonOK(不熟悉您正在使用的库;所以我可能有类型加载错误:它不是InternalServerError吗?)。

BTW:您的原始代码有一个非常有问题的一行:

Future[Try[_]]

val ll = res.value.get.get res.value。在Option[Try[T]]get上拨打Option通常是一个坏主意(即使在这种情况下由于TryAwait也不应该{ {1}},因此Option在技术上是安全的)因为它可以抛出异常。您最好使用Noneget和朋友。

答案 1 :(得分: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来获取它兼容的形式。他们的自述文件也有很多关于转换的有用信息以及存在的缺陷。