【问题标题】:Play framework async code dos not wait to result播放框架异步代码不等待结果
【发布时间】:2016-02-22 14:10:30
【问题描述】:

我有三个功能。

myFunc1:

def myFunc1(cluster: String, consumer: String) = Action.async { implicit request =>
  kafkaManager.getConsumerIdentity(cluster, consumer) map { errorOrT =>
    errorOrT.fold(
      error => BadRequest(Json.obj("msg" -> error.msg)),
      T=> {
        Ok(Json.obj("summary" -> getSummary(cluster, consumer, T.Map.keys)))
      })
}

获取摘要:

def getSummary(cluster: String, consumer: String, myMap: Iterable[String]) = {
  var topics: Map[String, JsObject] = Map()
  myMap.map { key =>
    topicSummary(cluster, consumer, x).map(r => {
      r.fold(l => {}, value => {
        topics += key -> value
      })
    })
  }
  topics
}

和主题摘要:

def topicSummary(cluster: String, consumer: String, topic: String) = {
  kafkaManager.getConsumedTopicState(cluster, consumer, topic).map { errorOrTopicSummary =>
    errorOrTopicSummary.map(
      topicSummary => {
        Json.obj("totalLag" -> topicSummary.totalLag.getOrElse(None).toString(), "percentageCovered" -> topicSummary.percentageCovered)
    })
  }
}

结果是:

{"summary":()}

问题在于 getSummary 没有等待结果。 我很想听听如何解决它的建议

【问题讨论】:

    标签: asynchronous playframework playframework-2.0 playframework-2.2


    【解决方案1】:

    很难准确判断发生了什么,因为您没有在函数中明确返回类型。假设所有 Kafka 调用都是异步的,似乎正在发生的是 topicSummary 返回一个 Future[JsObject],但调用它的 getSummary 不等待其结果,而是返回(空)主题映射立即。

    当您处理期货时,您需要:

    • 通过代码路径一直处理 Futures(推荐)
    • 明确地Await 实现其结果的未来(不推荐)

    您可以通过异步实现getSummary 来解决此问题,如下所示:

    myFunc1:

    def myFunc1(cluster: String, consumer: String) = Action.async { implicit request =>
      // NB: Since we're dealing with a Future within a Future, we
      // use flatMap to combine them
      kafkaManager.getConsumerIdentity(cluster, consumer).flatMap { errorOrT =>
        errorOrT.fold(
          error => 
            // In the case of an error, return a no-op Future with .successful
            Future.successful(BadRequest(Json.obj("msg" -> error.msg))),
    
          // Otherwise, map over the results of get summary
          T => getSummary(cluster, consumer, T.Map.keys).map { topics =>
            Ok(Json.obj("summary" -> topics))
          }
        )
      }
    }
    

    getSummary(近似代码):

    def getSummary(cluster: String, consumer: String, myMap: Iterable[String]): Future[Map[String, JsObject]] = {
    
      // For each key you expect a Future[JsObject], which you want to
      // transform into a tuple of key/object
      val topicKeys: List[Future[(String, JsObject)]] = myMap.toList.map { key =>
        topicSummary(cluster, consumer, key)
          // Map the future optional value with its key, defaulting
          // to an empty object
          .map(topicsOpt => key -> topicsOpt.getOrElse(Json.obj()))
    
          // OPTIONAL: handle any error with an empty object
          .recover {
            case _ => key -> Json.obj()
          }
      }
    
      // Finally, use Future.fold to turn a list of futures into a 
      // single Future sequence, then combine the (String, JsObject)
      // tuples into a map
      Future.fold(topicKeys)(Map.empty[String, JsObject])(_ + _)
    }
    

    在处理期货时,明确预期返回类型非常有用,至少在尝试理解中间状态时是这样。如果您最终得到太多嵌套地图和平面地图,请使用for 推导进行调查,以使事情看起来更清晰,但这是另一个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-27
      • 1970-01-01
      • 2021-05-10
      • 2016-12-05
      • 2018-08-28
      相关资源
      最近更新 更多