播放框架异步代码不等待结果

时间:2016-02-22 14:10:31

标签: asynchronous playframework playframework-2.0 playframework-2.2

我有三个功能。

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)))
      })
}

getSummary:

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
}

和topicSummary:

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没有等到结果。 我很想听听如何解决它的建议

1 个答案:

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

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