【问题标题】:Play 2.2 -Scala - How to chain Futures in Controller ActionPlay 2.2 -Scala - 如何在控制器动作中链接期货
【发布时间】:2013-11-02 01:35:27
【问题描述】:

我有 3 个响应类型的期货。第一个future返回一个JsValue,它定义是执行future 2和future 3还是只执行future 3。

伪代码: 如果 Future 1 那么 {future2 和 future 3} 否则未来 3

我试图在 play 框架动作中执行此操作,这意味着为了以后使用期货的结果,我不能使用 onSuccess、onFailure 和 onComplete,因为它们都返回 Unit 而不是上一个未来的实际 JsValue。

我尝试使用 map() 和 andThen 来做到这一点,但我是一个 Scala 菜鸟,我想我无法做到这一点,因为我总是错过了一点。这是我目前不起作用的方法!

def addSuggestion(indexName: String, suggestion: String) = Action.async {
  val indexExistsQuery: IndexExistsQuery = new IndexExistsQuery(indexName);
  val addSuggestionQuery: AddSuggestionQuery = new AddSuggestionQuery(indexName, suggestion)
  val indexCreationQuery: CreateCompletionsFieldQuery = new CreateCompletionsFieldQuery(indexName)

  val futureResponse: Future[Response] = for {
    responseOne <- EsClient.execute(indexExistsQuery)
    responseTwo <- EsClient.execute(indexCreationQuery) if (indexExistsQuery.getBooleanResult(indexExistsQuery.getResult(responseOne)))
    responseThree <- EsClient.execute(addSuggestionQuery)
  } yield responseThree

  futureResponse.map { response =>
  Ok("Feed title: " + (response.json))
}

【问题讨论】:

    标签: scala playframework future playframework-2.2


    【解决方案1】:

    我创建了一些伪代码:

    checkIndexExists() map {
      case true => Future.successful()
      case false => createIndex()
    } flatMap { _ =>
      query()
    }.map { response =>
      Ok("Feed title: " + (response.json))
    }.recover { 
      case _ => Ok("bla") 
    } 
    

    首先,如果索引存在,则启动查询。 然后你映射未来如何使用Future[Boolean],如果它成功的话。由于您使用地图,因此您可以提取Boolean。如果索引存在,您只需创建一个已经完成的未来。如果索引不存在,您需要启动索引创建命令。现在你有嵌套Future's (Future[Future[Response]]) 的情况。使用flatMap 删除一个维度,因此您只有Future[Response]。这可以映射到 Play 结果。

    更新(美信的实现):

      EsClient.execute(indexExistsQuery) map { response =>
          if (indexExistsQuery.getBooleanResult(indexExistsQuery.getResult(response))) Future.successful(Response)
          else EsClient.execute(indexCreationQuery)
        } flatMap { _ =>
          EsClient.execute(addSuggestionQuery)
        } map { response: Response =>
          Ok("Feed title: " + (response.json))
        }
    

    【讨论】:

    • 这里实现的解决方案,非常感谢:gist.github.com/MeiSign/d7ab401c717e8b8ef6b9
    • 为什么要在运行时创建索引?不应该提前完成吗?
    • 在我的用例中,索引有一个固定的映射,我希望能够在运行时创建它们。我们在这里谈论的是可以被视为内容容器的弹性搜索索引。
    【解决方案2】:

    我找到了这个解决方案,但我认为它不是一个好的解决方案,因为我正在使用 Await.result() 这是一个阻塞操作。 如果有人知道如何在不阻塞操作的情况下重构此代码,请告诉我。

    def addSuggestion(indexName: String, suggestion: String) = Action.async {
      val indexExistsQuery: IndexExistsQuery = new IndexExistsQuery(indexName);
      val addSuggestionQuery: AddSuggestionQuery = new AddSuggestionQuery(indexName, suggestion)
      val indexCreationQuery: CreateCompletionsFieldQuery = new CreateCompletionsFieldQuery(indexName)
    
      val indexExists: Boolean = indexExistsQuery.getBooleanResult(indexExistsQuery.getResult(Await.result(EsClient.execute(indexExistsQuery), 5.second)))
      if (indexExists) {
        EsClient.execute(addSuggestionQuery).map { response => Ok("Feed title: " + (response.json)) }
      } else {
        val futureResponse: Future[Response] = for {
          responseTwo <- EsClient.execute(indexCreationQuery)
          responseThree <- EsClient.execute(addSuggestionQuery)
        } yield responseThree
    
        futureResponse.map { response =>
          {
            Ok("Feed title: " + (response.json))
          }
        }.recover { case _ => Ok("bla") }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-04
      • 2018-06-15
      • 1970-01-01
      • 2022-01-22
      • 2021-03-17
      • 1970-01-01
      • 2019-04-11
      • 1970-01-01
      相关资源
      最近更新 更多