Параллельный рендеринг Playframework

#scala #playframework-2.0 #akka #iterate

#scala #playframework-2.0 #akka #итерация

Вопрос:

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

Например, если задача A завершается через 5 секунд, задача B завершается через 3 секунды, а задача C завершается через 1 секунду, вывод должен быть «C», «B», «A».

Следующие коды, похоже, выводят неправильный порядок и ожидают завершения всей задачи, прежде чем выводить результат.

 def lookup  = Action { implicit  req =>
    val a = Enumerator( Await.result(Promise.timeout("A", 5 seconds), 1 minute))
    val b = Enumerator( Await.result(Promise.timeout("B", 3 seconds), 1 minute))
    val c = Enumerator( Await.result(Promise.timeout("C", 1 second), 1 minute))

    val d = a >- b >- c

    Ok.chunked(d amp;> Comet(callback = "console.log"))
}
  

Комментарии:

1. Каков ваш фактический вариант использования? Этот код выглядит довольно надуманным, поскольку Await.result вложен в перечислитель.

2. @Ryan Я просто хотел смоделировать источники для Enumerator — это несколько заблокированных функций. Похоже Enumerator(someFunction) , я подумал, что было проще проиллюстрировать эту проблему.

Ответ №1:

Ваш код нарушен из-за того, как вы используете Await.result . Строка, которая определяет a , не завершается до Await.result тех пор, пока не вернется, и поэтому обещание для b никогда не начинается до тех пор, пока не закончится одно для a . Если вы используете что-то вроде:

 val a = Enumerator.flatten(Future.firstCompletedOf(List(
  Promise.timeout("A", 5 seconds),
  Promise.timeout(throw new Exception("A timed out"), 1 minute)
)).map(Enumerator(_)))
  

Вы получите правильное поведение.

Комментарии:

1. Спасибо, что указали на это, итак, каков обычный шаблон для этого случая — счетчики должны получать источники из разных def taskX:Future[X] источников?

2. Enumerator.flatten(future.map(Enumerator(_))) преобразует фьючерсы в счетчики, с которыми их затем можно комбинировать >- . Тайм-ауты действительно должны обрабатываться тем, что создает будущее, чтобы оно могло остановить то, что оно делает, когда срабатывает тайм-аут, например WSRequestHolder.withRequestTimeout , см.