Łączenie łańcuchów

WorkManager pozwala utworzyć i umieścić w kolejce łańcuch zadań, który określa wiele zależnych zadań i określa kolejność ich wykonywania. Ta funkcja jest szczególnie przydatna, gdy musisz uruchomić kilka zadań w określonej kolejności.

Aby utworzyć łańcuch zadań, możesz użyć WorkManager.beginWith(OneTimeWorkRequest) lub WorkManager.beginWith(List<OneTimeWorkRequest>), które zwracają wystąpienie WorkContinuation.

Następnie możesz użyć WorkContinuation, aby dodać zależne instancje OneTimeWorkRequest za pomocą then(OneTimeWorkRequest) lub then(List<OneTimeWorkRequest>).

Każde wywołanie metody WorkContinuation.then(...) zwraca nowe wystąpienie WorkContinuation. Jeśli dodasz List z OneTimeWorkRequest instancji, te żądania mogą potencjalnie być uruchamiane równolegle.

Na koniec możesz użyć metody WorkContinuation.enqueue(), aby enqueue() łańcucha WorkContinuation.

Przeanalizujmy przykład. W tym przykładzie skonfigurowane są 3 różne zadania instancji roboczych (potencjalnie równolegle). Wyniki tych instancji roboczych są łączone i przekazywane do zadania buforowania. Na koniec dane wyjściowe zadania są przekazywane do instancji roboczej przesyłającej, która przesyła wyniki na serwer zdalny.

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

Scalanie danych wejściowych

Gdy łączysz łańcuch instancji OneTimeWorkRequest, dane wyjściowe nadrzędnych żądań pracy są przekazywane jako dane wejściowe do elementów podrzędnych. W przykładzie powyżej dane wyjściowe funkcji plantName1, plantName2 i plantName3 zostaną przekazane jako dane wejściowe do żądania cache.

Do zarządzania danymi wejściowymi z wielu nadrzędnych żądań roboczych WorkManager używa metody InputMerger.

WorkManager udostępnia 2 różne typy InputMerger:

  • OverwritingInputMerger próbuje dodać do danych wyjściowych wszystkie klucze ze wszystkich danych wejściowych. W razie konfliktów zastępuje wcześniej ustawione klucze.

  • ArrayCreatingInputMerger próbuje scalić dane wejściowe, aby w razie potrzeby utworzyć tablice.

Jeśli masz bardziej konkretny przypadek użycia, możesz utworzyć własny, podklasyfikując InputMerger.

Zastąpienie scalania danych wejściowych

OverwritingInputMerger jest domyślną metodą scalania. Jeśli w przypadku scalania wystąpią konflikty kluczy, najnowsza wartość klucza zastąpi wszelkie wcześniejsze wersje w wynikowych danych.

Jeśli np. dane wejściowe rośliny mają klucz pasujący do swoich nazw zmiennych ("plantName1", "plantName2" i "plantName3"), dane przekazywane do instancji roboczej cache będą miały 3 pary klucz-wartość.

Diagram przedstawiający 3 zadania przekazujące różne dane wyjściowe do następnego zadania w łańcuchu. Ponieważ dane wyjściowe mają różne klucze, następne zadanie otrzyma 3 pary klucz/wartość.

W przypadku konfliktu ostatnia instancja robocza, która wykonała zadanie „wygrane”, jest przekazywana do funkcji cache.

Diagram przedstawiający 3 zadania przekazujące dane wyjściowe do następnego zadania w łańcuchu. W takim przypadku 2 z tych zadań dają dane wyjściowe z tym samym kluczem. W rezultacie następne zadanie otrzyma 2 pary klucz-wartość, a 1 z sprzecznych danych wyjściowych zostanie pominięty.

Żądania pracy są realizowane równolegle, więc nie możesz mieć gwarancji kolejności, w jakiej będą realizowane. W przykładzie powyżej plantName1 może zawierać wartość "tulip" lub "elm", w zależności od tego, która wartość jest zapisywana jako ostatnia. Jeśli istnieje ryzyko konfliktu kluczy i chcesz zachować wszystkie dane wyjściowe w ramach scalania, lepszym rozwiązaniem może być użycie ArrayCreatingInputMerger.

Metoda scalania tabel

W podanym wyżej przykładzie chcemy zachować dane wyjściowe wszystkich instancji roboczych o nazwach roślin, dlatego użyjemy właściwości 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 paruje każdy klucz z tablicą. Jeśli każdy z kluczy jest unikalny, wynik jest szeregiem jednoelementowych tablic.

Diagram przedstawiający 3 zadania przekazujące różne dane wyjściowe do następnego zadania w łańcuchu. Następne zadanie jest przekazywane do 3 tablic, po 1 na każdy klucz wyjściowy. Każda tablica ma 1 element.

Jeśli wystąpią konflikty kluczy, wszystkie odpowiadające im wartości zostaną zgrupowane w tablicy.

Diagram przedstawiający 3 zadania przekazujące dane wyjściowe do następnego zadania w łańcuchu. W takim przypadku 2 z tych zadań dają dane wyjściowe z tym samym kluczem. Następne zadanie jest przekazywane 2 tablice, po 1 na każdy klucz. Jedna z tych tablic ma 2 elementy, ponieważ istniały 2 wyniki z tym kluczem.

Stany związane z łańcuchami i pracą

Łańcuchy obiektów OneTimeWorkRequest są wykonywane po kolei, o ile ich praca zakończy się powodzeniem (czyli zwraca wartość Result.success()). Podczas wykonywania żądania pracy mogą się zakończyć niepowodzeniem lub anulować, co ma wpływ na zależne żądania pracy.

Gdy pierwsze OneTimeWorkRequest zostanie umieszczone w kolejce w łańcuchu żądań pracy, wszystkie kolejne są blokowane do momentu zakończenia tego pierwszego.

Diagram przedstawiający łańcuch zadań. Pierwsze zadanie jest w kolejce. Wszystkie kolejne są blokowane do momentu zakończenia pierwszego.

Po umieszczeniu w kolejce i spełnieniu wszystkich ograniczeń zadania rozpoczyna się pierwsze żądanie. Jeśli zadanie zostanie wykonane w katalogu głównym OneTimeWorkRequest lub List<OneTimeWorkRequest> (czyli zwróci wartość Result.success()), w kolejce pojawi się następny zestaw zależnych żądań roboczych.

Diagram przedstawiający łańcuch zadań. Pierwsze zadanie zostało wykonane, a 2 jego następców znajduje się w kolejce. Pozostałe zadania są zablokowane.

Jeśli każde żądanie pracy zostanie zrealizowane, ten sam wzorzec będzie promował resztę łańcucha żądań, aż wszystkie zadania zostaną wykonane w łańcuchu. Chociaż jest to najprostszy i często preferowany przypadek, stany błędów są równie ważne, jak ich obsługa.

Jeśli podczas przetwarzania Twojego żądania służbowego przez instancję roboczą wystąpi błąd, możesz spróbować to żądanie jeszcze raz zgodnie ze zdefiniowaną przez Ciebie zasadą ponawiania. Ponowienie żądania, które jest częścią łańcucha, oznacza, że tylko to żądanie zostanie wykonane z dostarczonymi do niego danymi wejściowymi. Nie będzie to miało wpływu na pracę wykonywaną równolegle.

Diagram przedstawiający łańcuch zadań. Jedno z zadań zakończyło się niepowodzeniem, ale miało zdefiniowaną zasadę ponawiania. Zadanie zostanie ponownie uruchomione po upływie odpowiedniego czasu. Kolejne zadania w łańcuchu są blokowane, dopóki nie zostanie poprawnie uruchomiona.

Więcej informacji o definiowaniu niestandardowych strategii ponawiania prób znajdziesz w artykule Zasady ponawiania i ponawiania.

Jeśli ta zasada ponawiania jest niezdefiniowana lub wyczerpana albo jeśli w inny sposób osiągniesz stan, w którym OneTimeWorkRequest zwraca wartość Result.failure(), to żądanie i wszystkie zależne żądania są oznaczone jako FAILED.

Diagram przedstawiający łańcuch zadań. Jedno zadanie zakończyło się niepowodzeniem i nie można go ponowić. W rezultacie wszystkie kolejne zadania w łańcuchu także kończą się niepowodzeniem.

Ta sama logika obowiązuje w przypadku anulowania OneTimeWorkRequest. Żądania pracy zależnej również są oznaczone jako CANCELLED, a ich praca nie jest wykonywana.

Diagram przedstawiający łańcuch zadań. Jedno zadanie zostało anulowane. W rezultacie wszystkie kolejne zadania w łańcuchu także zostaną anulowane.

Pamiętaj, że jeśli chcesz dołączyć więcej żądań pracy do łańcucha, którego przetwarzanie zakończyło się niepowodzeniem lub które je anulowało, nowo dołączone zlecenie również zostanie oznaczone odpowiednio FAILED lub CANCELLED. Jeśli chcesz przedłużyć działanie istniejącej sieci, zapoznaj się z opisem APPEND_OR_REPLACE w Istniejącej zasadzie.

Podczas tworzenia łańcuchów żądań pracy zależne żądania powinny określać zasady ponawiania próby, aby zadania były zawsze wykonywane w odpowiednim czasie. Nieudane prośby o pracę mogą skutkować niepełnymi łańcuchami lub nieoczekiwanym stanem.

Więcej informacji znajdziesz w artykule Anulowanie i zatrzymywanie pracy.