Выведите два варианта будущего, когда они завершатся в Play 2.5.

Я смиренно возвращаюсь к сообществу, поскольку сейчас я явно слишком глубоко увяз.

Итак, я пытаюсь вернуть два фьючерса (в Play 2.5.2 в Scala) на экран в виде модулей, которые появляются на экране после их завершения. Я пробовал довольно много способов сделать это. Во-первых, отметим, что мне удалось успешно транслировать два источника с повторяющимся расписанием:

  def streamAction = Action { request =>

    val source1: Source[String, NotUsed] = unfoldAsync(NotUsed) { _ ⇒
      sc.makeServiceCall("stream1").map(x ⇒ Some(NotUsed → x))
    }

    val source2: Source[String, NotUsed] = unfoldAsync(NotUsed) { _ ⇒
      sc.makeServiceCall("stream2").map(x ⇒ Some(NotUsed → x))
    }

    Ok.chunked(source1.merge(source2))
  }

Где sc.makeServiceCall относится к:

   class ServiceClient @Inject() (ws: WSClient) {

     def makeServiceCall(serviceName: String): Future[String] = {
       ws.url(s"http://localhost:9000/mock/$serviceName").get().map(_.body)
     }

   }

Который звонит:

   class Mock @Inject() (actorSystem: ActorSystem)(implicit exec: ExecutionContext) extends Controller {

     def mock(serviceName: String) = Action.async { request =>
       serviceName match {
         case "async1" => respond("asy1", 0.second)
         case "async2" => respond("asy2", 3.second)
         case "async3" => respond("asy3", 5.second)
         case "stream1" => schedule("first", 500.millisecond)
         case "stream2" => schedule("second", 2000.millisecond)
       }
     }

     private def schedule(data: String, delay: FiniteDuration): Future[Result] = {
       akka.pattern.after(delay, actorSystem.scheduler){Future.successful(Ok(data))}
     }

     private def respond(data: String, delay: FiniteDuration): Future[Result] = {
       val promise: Promise[Result] = Promise[Result]()
       actorSystem.scheduler.scheduleOnce(delay) { promise.success(Ok(data)) }
       promise.future
     }

   }

Итак, это работает (как уже упоминалось) с выводом потока следующим образом:

первыйпервыйпервыйвторойпервыйпервыйпервыйпервыйвторойпервыйпервыйпервыйпервыйвторой

Но при попытке вывести два фьючерса, когда они завершатся (только по одному разу), я не могу. Я пробовал это:

 def outputAction = Action { request =>

   val source1: Source[String, NotUsed] = Source.fromFuture(sc.makeServiceCall("async1"))
   val source2: Source[String, NotUsed] = Source.fromFuture(sc.makeServiceCall("async2"))

   Ok.chunked(source1.merge(source2))
 }

Это просто выводит все сразу (когда завершится 2-е будущее)

asys1asys2

Что я делаю неправильно?


person jesus g_force Harris    schedule 05.06.2017    source источник
comment
Что вы используете для вызова действия? На стороне клиента может быть некоторый буфер. Используя curl, вы можете избежать этого, используя опцию -N.   -  person Cyrille Corpet    schedule 06.06.2017
comment
@CyrilleCorpet - да, буфер может быть проблемой, но у меня также возникают проблемы с cURL как вы увидите здесь, поэтому я не могу знать наверняка. Так бы вы поступили или делали это раньше?   -  person jesus g_force Harris    schedule 06.06.2017
comment
У меня были некоторые проблемы с буферизацией для потоковой передачи с Play и cURL, решенные с помощью -N. Однако они не были связаны с объединенными потоками (это было в Play-2.3.8, где потоки предъявляли иск Iteratee, а не akka-потоки).   -  person Cyrille Corpet    schedule 06.06.2017
comment
@CyrilleCorpet Как я уже сказал, у меня проблемы с cURL (в командной строке), который возвращает GET / HTTP/1.1, а не какие-либо результаты, и никто не смог мне помочь, почему. Я хотел бы проверить, является ли это проблемой буферизации. Я использую Play 2.5.2   -  person jesus g_force Harris    schedule 06.06.2017


Ответы (1)


Как сказано в комментариях, это похоже на проблему с кешем на стороне вашего клиента:

Я использовал следующий код и назвал curl -N localhost:9000/stream

def streamAction = Action { request =>

  val source1: Source[String, NotUsed] = Source.single("async1")

  val source2: Source[String, NotUsed] = Source.single("async2").initialDelay(3.seconds)

  val merged: Source[String, NotUsed] = source1.merge(source2)

  Ok.chunked(merged)
}

Это вернуло async1 и через 3 секунды async2, как и ожидалось.

person Cyrille Corpet    schedule 06.06.2017
comment
Спасибо, но это только рендерит (оба результата вместе) за 3,03 секунды, то есть вскоре после завершения более длинного будущего (source2). Но я не могу протестировать cURL, как уже упоминалось, потому что у меня есть эти проблемы. - person jesus g_force Harris; 06.06.2017
comment
Да, но мои тесты показывают, что у вас проблема с буфером в вашем клиенте, а не с потоковой передачей в Play. - person Cyrille Corpet; 06.06.2017
comment
Мне бы очень хотелось увидеть это для себя, но, как я уже сказал, у меня проблемы с портами, как вы увидите здесь. Я не хочу слишком далеко отходить от исходного вопроса, но, поскольку это уместно, могу ли я спросить, как вы настроили cURL с Play? - person jesus g_force Harris; 06.06.2017
comment
Давайте продолжим этот разговор здесь: chat.stackoverflow. com/комнаты/145987/ - person Cyrille Corpet; 06.06.2017