2017-01-26 2 views
2

У нас есть веб-приложение Scala Play, которое выполняет ряд операций с базой данных как часть HTTP-запроса, каждый из которых является Будущим. Обычно мы создаем фьючерсы для действия контроллера асинхронного действия и позволяем Play handle ждать их.Нужно ли ждать всех фьючерсов, чтобы гарантировать их исполнение?

Но я также заметил, что в ряде мест мы не пузырием будущее или даже дождались его завершения. Я думаю, что это плохо, потому что это означает, что HTTP-запрос не сработает, если будущее не удастся, но действительно ли это даже гарантирует, что будущее будет выполнено вообще, потому что ничего не ждет от его результата? Будет ли проигрывать не ожидаемые фьючерсы после того, как HTTP-запрос будет отправлен, или оставить их в фоновом режиме?

ответ

2

TL; DR

  1. Play не будет убивать Future с после отправки ответа HTTP.
  2. Ошибки не сообщаются, если какой-либо из ваших Future сбой.

Длинная версия

Ваши фьючерсы не будут убиты, когда ответ HTTP был отправлен. Вы можете попробовать это для себя так:

def futuresTest = Action.async { request => 

    println(s"Entered futuresTest at ${LocalDateTime.now}") 

    val ignoredFuture = Future{ 
     var i = 0 
     while (i < 10) { 
     Thread.sleep(1000) 
     println(LocalDateTime.now) 
     i += 1 
     } 
    } 

    println(s"Leaving futuresTest at ${LocalDateTime.now}") 

    Future.successful(Ok) 
    } 

Однако вы правы, что запрос не будет ошибкой, если какой-либо из фьючерсов терпят неудачу. Если это проблема, вы можете составить фьючерсы, используя для понимания или flatКарты. Вот пример того, что вы можете сделать (я предполагаю, что ваш Фьючерс выполнять только боковые видеоэффекты (Future[Unit])

Для того, чтобы ваши фьючерсы выполнить в paralell

val dbFut1 = dbCall1(...) 
val dbFut2 = dbCall2(...) 
val wsFut1 = wsCall1(...) 
val fut = for(
    _ <- dbFut1; 
    _ <- dbFut2; 
    _ <- wsFut1 
) yield() 

fut.map(_ => Ok) 

Чтобы их выполнить в последовательности

val fut = for(
    _ <- dbCall1(...); 
    _ <- dbCall2(...); 
    _ <- wsCall2(...) 
) yield() 

fut.map(_ => Ok) 
1

делает это на самом деле даже гарантировать будущее будет выполняться на всех, , так как ничего не будет ждать результата этого? Сыграет падение не ожидаемые фьючерсы после запроса HTTP-запроса или оставить бегущих в фоновом режиме?

Этот вопрос фактически проходит намного глубже, чем Игра. Вы обычно спрашиваете: «Если я не буду ждать синхронно в будущем, как я могу гарантировать, что он действительно завершится без GCed?». Чтобы ответить на это, нам нужно понять, как GC фактически просматривает потоки. С точки зрения GC поток - это то, что мы называем «root». Такой корень является отправной точкой для кучи, чтобы пересечь его объекты и посмотреть, какие из них имеют право на сбор. Среди корней также есть статические поля, например, которые, как известно, живут на протяжении всего срока службы приложения.

Итак, когда вы его просмотр, как это, и думать о какой Future на самом деле делает, что очереди функции, которая работает на выделенный поток из пула потоков, доступных через нижележащий ExecutorService (который мы называем ExecutionContext в Scala), вы видите, что, хотя вы не ожидаете завершения, среда выполнения JVM гарантирует, что ваш Future будет запущен до завершения.Что касается объекта Future, который обертывает функцию, он содержит ссылку на это незавершенное тело функции, поэтому сам Future не собирается.

Когда вы думаете об этом с этой точки зрения, это вполне логично, так как выполнение Future происходит асинхронно, и мы обычно продолжаем обрабатывать его в асинхронном режиме с помощью продолжений, таких как map, flatMap, onComplete и т.д.