С игрой и akka-https: как правильно связать несколько запросов с входящим запросом, чтобы создать ответ?

Поэтому я попытался заставить небольшое игровое приложение общаться с другой службой отдыха. Идея состоит в том, чтобы получить запрос на стороне воспроизведения, а затем сделать запрос к остальным API и передать части результата другому локальному участнику, прежде чем отображать ответ от локального участника и остального сервиса в браузере. На этом изображении показано, как

И я попытался сделать это с потоками. У меня все работает, но я абсолютно не доволен той частью, где я разговариваю с моим локальным актером и создаю кортеж Future[(Future[String],Future[String]), поэтому я был бы рад, если бы вы могли указать мне направление, как сделать это элегантно и чистый способ.

Итак, вот мой код. Ввод представляет собой файл csv. Мой местный актер создает дополнительную графику, которую я хочу поместить в ответ.

def upload = Action.async(parse.multipartFormData) { request =>
 request.body.file("input").map { inputCsv =>

 //csv to list of strings
 val inputList: List[String] = convertFileToList(inputCsv)

 //http request to rest service
 val responseFuture: Future[HttpResponse] = httpRequest(inputList, "/path",4321 ,"0.0.0.0")

 //pattern match response and ask local actor
 val formattedResult = responseFuture.flatMap { response =>
  response.status match {
    case akka.http.scaladsl.model.StatusCodes.OK =>
      val resultTeams = Unmarshal(response.entity).to[CustomResultCaseClass]

     //the part I'd like to improve
      val tupleFuture = resultTeams.map(result => 
        (Future(result.teams.reduce(_ + "," + _)),
          plotter.ask(PlotData(result.eval)).mapTo[ChartPath].flatMap(plotAnswer => Future(plotAnswer.path))))
      tupleFuture.map(tuple => tuple._1.map(teams => 
        p._2.map(chartPath => Ok(views.html.upload(teams))(chartPath))))).flatMap(a => a).flatMap(b => b)
   }
 }
 formattedResult
}.getOrElse(Future(play.api.mvc.Results.BadRequest))
}

person rincewind    schedule 26.02.2016    source источник


Ответы (1)


Для понимания полезны для этого типа вариантов использования. Базовый пример, демонстрирующий задействованный рефакторинг:

val teamFut = Future(result.teams.reduce(_ + "," + _))

//I think the final .flatMap(Future(_.path)) is unnecessary it should be
// .map(_.path), but I wanted to replicate the question code functionality
val pathFut = plotter.ask(PlotData(result.eval))
                     .mapTo[ChartPath]
                     .flatMap(Future(_.path))

val okFut = 
  for {
    teams     <- teamFut
    chartPath <- pathFut      
  } yield Ok(views.html.upload(teams))(chartPath)

Примечание. Исходные фьючерсы должны быть созданы вне , иначе параллельное выполнение не произойдет.

person Ramón J Romero y Vigil    schedule 26.02.2016
comment
Спасибо! Кажется, это именно тот инструмент, который здесь нужен. Как вы в целом считаете, что то, как я это реализовал, является хорошим, или вы подошли бы к этому по-другому? - person rincewind; 27.02.2016
comment
@rincewind Добро пожаловать. В целом ваша реализация выглядит нормально. Просто будьте осторожны, не злоупотребляйте фьючерсами, поскольку при создании экземпляра возникают значительные первоначальные затраты. Например, result.teams должно быть довольно большим, чтобы гарантировать будущее всего за reduce. Удачного взлома. - person Ramón J Romero y Vigil; 27.02.2016