Объединение работ

WorkManager позволяет создавать и ставить в очередь цепочки задач, которые зависят друг от друга и должны выполняться в определенном порядке. Это особенно полезно, когда нужно выполнить несколько задач в определенном порядке.

Чтобы создать цепочку задач, используйте WorkManager.beginWith(OneTimeWorkRequest) или WorkManager.beginWith(List<OneTimeWorkRequest>). Каждый из этих методов возвращает экземпляр WorkContinuation.

Затем WorkContinuation можно использовать для добавления зависимых экземпляров OneTimeWorkRequest с помощью then(OneTimeWorkRequest) или then(List<OneTimeWorkRequest>).

Каждый вызов WorkContinuation.then(...) возвращает новый экземпляр WorkContinuation. Если вы добавите List из OneTimeWorkRequest экземпляров, эти запросы могут выполняться параллельно.

Наконец, вы можете использовать метод WorkContinuation.enqueue(), чтобы enqueue() цепочку WorkContinuation.

Рассмотрим пример. В этом примере настроено выполнение трех разных заданий Worker (возможно, параллельно). Результаты работы этих рабочих ВМ объединяются и передаются в задание рабочей ВМ, выполняющей кеширование. Наконец, выходные данные этой задачи передаются в Worker, который загружает результаты на удаленный сервер.

Kotlin

WorkManager.getInstance(myContext)
   // Candidates to run in parallel
   .beginWith(listOf(plantName1, plantName2, plantName3))
   // Dependent work (only runs after all previous work in chain)
   .then(cache)
   .then(upload)
   // Call enqueue to kick things off
   .enqueue()

Java

WorkManager.getInstance(myContext)
   // Candidates to run in parallel
   .beginWith(Arrays.asList(plantName1, plantName2, plantName3))
   // Dependent work (only runs after all previous work in chain)
   .then(cache)
   .then(upload)
   // Call enqueue to kick things off
   .enqueue();

Объединение входных данных

При создании цепочки экземпляров OneTimeWorkRequest выходные данные родительских запросов на работу передаются в качестве входных данных дочерним запросам. В примере выше выходные данные plantName1, plantName2 и plantName3 будут переданы в качестве входных данных в запрос cache.

Чтобы управлять входными данными из нескольких родительских рабочих запросов, WorkManager использует InputMerger.

WorkManager предоставляет два типа InputMerger:

  • OverwritingInputMerger пытается добавить все ключи из всех входных данных в выходные. В случае конфликтов он перезаписывает ранее заданные ключи.

  • ArrayCreatingInputMerger пытается объединить входные данные, при необходимости создавая массивы.

Если у вас есть более конкретный вариант использования, вы можете написать собственный подкласс InputMerger.

OverwritingInputMerger

OverwritingInputMerger – метод объединения по умолчанию. Если при объединении возникнут конфликты ключей, то последнее значение ключа перезапишет все предыдущие версии в итоговых выходных данных.

Например, если у каждого входного значения завода есть ключ, соответствующий названию переменной ("plantName1", "plantName2" и "plantName3"), то данные, переданные исполнителю cache, будут содержать три пары "ключ-значение".

Диаграмма, на которой показаны три задания, передающие разные выходные данные следующему заданию в цепочке. Поскольку у всех трех выходных значений разные ключи, следующее задание получает три пары &quot;ключ-значение&quot;.

Если возникает конфликт, то "побеждает" последний завершивший работу исполнитель, и его значение передается в cache.

Диаграмма, на которой показаны три задания, передающие выходные данные следующему заданию в цепочке. В этом случае два задания создают выходные данные с одним и тем же ключом. В результате следующее задание получает две пары &quot;ключ-значение&quot;, а один из конфликтующих выходных файлов удаляется.

Поскольку запросы на выполнение заданий обрабатываются параллельно, порядок их выполнения не гарантируется. В примере выше plantName1 может иметь значение "tulip" или "elm" в зависимости от того, какое значение было записано последним. Если есть вероятность конфликта ключей и вам нужно сохранить все выходные данные при объединении, лучше использовать ArrayCreatingInputMerger.

ArrayCreatingInputMerger

В приведенном выше примере, поскольку мы хотим сохранить выходные данные всех исполнителей, связанных с названиями растений, следует использовать ArrayCreatingInputMerger.

Kotlin

val cache: OneTimeWorkRequest = OneTimeWorkRequestBuilder<PlantWorker>()
   .setInputMerger(ArrayCreatingInputMerger::class)
   .setConstraints(constraints)
   .build()

Java

OneTimeWorkRequest cache = new OneTimeWorkRequest.Builder(PlantWorker.class)
       .setInputMerger(ArrayCreatingInputMerger.class)
       .setConstraints(constraints)
       .build();

ArrayCreatingInputMerger сопоставляет каждый ключ с массивом. Если каждый из ключей уникален, результатом будет серия массивов из одного элемента.

Диаграмма, на которой показано, как три задания передают разные выходные данные следующему заданию в цепочке. Следующему заданию передаются три массива, по одному для каждого выходного ключа. Каждый массив содержит один элемент.

Если ключи совпадают, соответствующие значения группируются в массив.

Диаграмма, на которой показаны три задания, передающие выходные данные следующему заданию в цепочке. В этом случае два задания создают выходные данные с одним и тем же ключом. Следующему заданию передаются два массива, по одному для каждого ключа. Один из этих массивов содержит два элемента, поскольку с этим ключом было два выходных значения.

Связывание и статусы работы

Цепочки OneTimeWorkRequest выполняются последовательно, пока их работа не будет успешно завершена (то есть они возвращают Result.success()). Запросы на работу могут завершиться ошибкой или быть отменены во время выполнения, что повлияет на зависимые запросы на работу.

Когда первый запрос OneTimeWorkRequest ставится в очередь в цепочке запросов на работу, все последующие запросы блокируются до тех пор, пока не будет выполнена работа по первому запросу.

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

После постановки в очередь и выполнения всех ограничений на работу начинается выполнение первого запроса на работу. Если работа в корневом объекте OneTimeWorkRequest или List<OneTimeWorkRequest> успешно завершена (то есть возвращает Result.success()), то в очередь добавляется следующий набор зависимых запросов на работу.

Диаграмма, показывающая цепочку заданий. Первое задание выполнено, а два следующих за ним поставлены в очередь. Остальные задания заблокированы до завершения предыдущих.

Если каждый запрос на работу выполняется успешно, этот же шаблон распространяется на остальную часть вашей цепочки запросов на работу, пока не будет завершена вся работа в цепочке. Это самый простой и часто предпочтительный вариант, но не менее важно обрабатывать состояния ошибок.

Если при обработке запроса на выполнение задачи возникает ошибка, вы можете повторить запрос в соответствии с заданными правилами отсрочки. Повторная попытка выполнения запроса, который является частью цепочки, означает, что будет повторен только этот запрос с предоставленными ему входными данными. Это не повлияет на параллельно выполняемые задачи.

Диаграмма, показывающая цепочку заданий. Одно из заданий не выполнено, но для него заданы правила экспоненциальной задержки. Задание будет перезапущено по истечении соответствующего периода времени. Последующие задания в цепочке будут заблокированы, пока оно не будет выполнено.

Дополнительную информацию о настройке собственных стратегий повторных попыток можно найти в правилах повторных попыток и отсрочки.

Если правила повторных попыток не определены или исчерпаны или вы достигли состояния, в котором OneTimeWorkRequest возвращает Result.failure(), то этот запрос на работу и все зависимые запросы помечаются как FAILED..

Диаграмма, показывающая цепочку заданий. Одно задание не удалось выполнить, и повторить его нельзя. В результате все последующие задания в цепочке также не выполняются.

Та же логика применяется при отмене OneTimeWorkRequest. Все зависимые запросы на работу также помечаются как CANCELLED и не выполняются.

Диаграмма, показывающая цепочку заданий. Одно задание отменено. В результате все последующие задания в цепочке также отменяются.

Если вы добавите новые запросы на выполнение работы в цепочку, в которой есть отмененные запросы или запросы, завершившиеся ошибкой, то новые запросы также будут помечены как FAILED или CANCELLED соответственно. Если вы хотите расширить работу существующей цепочки, ознакомьтесь с APPEND_OR_REPLACE в ExistingWorkPolicy.

При создании цепочек рабочих запросов для зависимых запросов следует определить правила повторных попыток, чтобы обеспечить своевременное выполнение работы. Неудачные запросы на работу могут привести к неполным цепочкам и/или неожиданному состоянию.

Подробнее об отмене и остановке работы…