2016-04-18 4 views
0

У меня есть приложение на Play 2.4 (Java) с некоторыми фоновыми задачами Akka, реализованными как функции, возвращающие Promise.Play Framework 2.4 Последовательный запуск нескольких обещаний

  • Task1 загружает банковские выписки через банк Rest API.
  • Task2 обрабатывает заявления и связывает их с клиентами.
  • Task3 делает некоторые другие обработки.

Task2 не может работать до того, как Task1 завершит свою работу. Task3 не может работать до Task2. Я пытался запустить их через последовательность Promise.map() так:

protected F.Promise run() throws WebServiceException { 
     return bankAPI.downloadBankStatements().map(
       result -> bankProc.processBankStatements().map(
         _result -> accounting.checkCustomersBalance())); 
} 

Я был под впечатлением, что первая карта будет ждать, пока TASK1 не будет сделано, и тогда он будет вызывать TASK2 и так далее. Когда я смотрю в приложение (задачи записывают некоторую информацию об отладке в журнал), я вижу, что задачи выполняются параллельно.

Я также пытался использовать Promise.flatMap() и Promise.sequence(), не повезло. Задачи всегда работают параллельно.

Я знаю, что Play является неблокирующим приложением в природе, но в этой ситуации мне действительно нужно делать что-то в правильном порядке.

Есть ли общая практика о том, как выполнять несколько обещаний в выбранном порядке?

ответ

0

Вы вложенности второй вызов map, а это значит, что здесь происходит это

  1. processBankStatements
  2. checkCustomerBalance
  3. downloadBankStatements

Вместо этого вам нужно приковать их:

protected F.Promise run() throws WebServiceException { 
    return bankAPI.downloadBankStatements() 
        .map(statements -> bankProc.processBankStatements()) 
        .map(processedStatements -> accounting.checkCustomersBalance()); 
} 

Я замечаю, что вы не используете result или _result (который я переименовал для ясности) - это намеренно?

+0

Ну, я использую 'F.Promise.promise (лямбда)', который возвращается 'processBankStatements' и' checkCustomerBalance'. Обещания не могут иметь недействительный тип результата, поэтому я возвращаю null от обещания. Таким образом, результаты не имеют значения. Все три функции/обещания выполняют некоторые задания в базе данных, и они ничего не возвращают. Единственная цель - запустить эти задания в выбранном порядке. Я знаю, что это не хороший подход и хорошее использование функций Play, но в этом случае это необходимо. В любом случае спасибо за совет. Я попробую. – spidla

+0

Это не проблема, если возвращаемое значение не требуется, я просто проверял, что ответ был завершен. –

+0

Ну, это не работает. Теперь все три обещания начинаются параллельно. – spidla

0

Хорошо, я нашел решение. Правильный ответ:

Если вы цепляете несколько обещаний так, как я. Это означает, что в обмен map() функции вы ожидаете другой Promise.map() функции и так далее, вы должны следовать этим правилам:

  • Если вы возвращаете, не являющиеся фьючерсные от отображения, просто использовать map()
  • Если вы возвращаете больше фьючерсов от картографирования, вы должны использовать flatMap()

правильный фрагмент кода для моего случая тогда:

return bankAPI.downloadBankStatements().flatMap(result -> { 
     return bankProc.processBankStatements().flatMap(_result -> { 
      return accounting.checkCustomersBalance().map(__result -> { 
       return null; 
      }); 
     }); 
}); 

Это решение было предложено мне давно, но сначала оно не работало.Проблема заключалась в том, что у меня была скрытая Promise.map() функция внутри downloadBankStatements(), так что в этом случае цепочка flatMaps была сломана.

+0

Вдохновение этого ответа взято из [здесь] (http://stackoverflow.com/questions/25554687/chaining-of-promises-via-flatmap-in-play-controller-action) – spidla