Scala HttpService上的wait.result

Scala HttpService上的wait.result,scala,future,slick-3.0,http4s,http4s-circe,Scala,Future,Slick 3.0,Http4s,Http4s Circe,我有一个scala项目,其中包含http4s 0.15.16a和slick 3.2.1,包括以下步骤: 通过rest呼叫接收ID 将ID传递给MySlickDAO,并用未来进行响应 调用myclickdao返回的Future上的wait.result(res,Duration.Inf) 创建json 问题是我使用了Await.result,这是不好的做法 有更好的解决办法吗 代码如下: val service = HttpService { //http://localhost:8080/

我有一个scala项目,其中包含http4s 0.15.16a和slick 3.2.1,包括以下步骤:

  • 通过rest呼叫接收ID
  • 将ID传递给MySlickDAO,并用未来进行响应
  • 调用myclickdao返回的Future上的wait.result(res,Duration.Inf)
  • 创建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 ....
    

    }

    您可以将一个
    未来的结果链接到另一个
    而不是等待:

    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)
    }
    
    这样做的结果将是
    未来
    的一个常见超类型
    jsonOK
    InternalServerError
    (不熟悉您正在使用的库;因此我可能有错误的加载类型:这不是
    未来[Try[\u]]
    是吗?)

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

    val ll = res.value.get.get
    

    res.value
    是一个
    选项[Try[T]]
    。在
    选项
    尝试
    上调用
    获取
    通常是个坏主意(即使在这种情况下,由于
    等待
    选项
    永远不应该是
    ,因此
    获取
    在技术上是安全的),因为它可能引发异常。您最好使用
    map
    flatMap
    和friends。

    问题是,http4s 0.15使用Scalaz并发结构,而Slick使用本机Scala结构,这两种结构不适合彼此工作。我的理解是,http4s0.17+已经从Scalaz转换为Cats,这可能需要使用原生Scala期货,因此如果您可以升级,这可能值得一试。如果没有,您可以通过手动创建一个包装您未来的任务来处理转换:

    def scalaFutureRes = MySlickDAO.load(id)
    val scalazTaskRes = Task.async { register =>
      scalaFutureRes.onComplete {
        case Success(success) => register(success.right)
        case Failure(ex)      => register(ex.left)
      }
    }
    
    此时,您已经从未来的[ResultType]中获得了一个任务[ResultType],您可以将其映射/平面映射到您的其余逻辑,如Levi的回答中所示


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

    为什么要将
    未来
    阻塞?@cchantep我等待未来完成为什么?这不是使用
    Future
    (它已经失去了所有的兴趣)的通常方式。jsonOK是OK:defjsonok(s1:Json)的包装器:Task[Response]=OK(removeNull(s1))。putHeaders(Header(“内容类型”,“应用程序/Json”)等等?这仍然是阻塞(还有不安全的
    .get
    )map返回未来而不是任务[Response],因此问题仍然存在:scala.concurrent.Future[scalaz.concurrent.Task[org.http4s.Response]]required:scalaz.concurrent.Task[org.http4s.Response]resFut.map{record=>