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

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 .

Давайте рассмотрим пример. В этом примере 3 разных задания Worker настроены на выполнение (потенциально параллельно). Результаты этих 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 .

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

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