Цепная работа

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

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

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

Every invocation of the WorkContinuation.then(...) returns a new instance of WorkContinuation . If you add a List of OneTimeWorkRequest instances, these requests can potentially run in parallel.

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

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

Котлин

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()

Ява

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 .

ПерезаписьInputMerger

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

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

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

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

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

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

ArrayCreatingInputMerger

Для приведенного выше примера, учитывая, что мы хотим сохранить выходные данные всех рабочих с именем завода, нам следует использовать ArrayCreatingInputMerger .

Котлин

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

Ява

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 .

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

Более подробную информацию см. в разделе Отмена и прекращение работ .