Concatenamento dei lavori

Con WorkManager puoi creare e accodare una catena di lavoro che specifica più attività dipendenti e ne definisce l'ordine di esecuzione. Questa funzionalità è particolarmente utile quando devi eseguire diverse attività in un determinato ordine.

Per creare una catena di lavoro, puoi utilizzare WorkManager.beginWith(OneTimeWorkRequest) o WorkManager.beginWith(List<OneTimeWorkRequest>), ciascuno che restituisce un'istanza di WorkContinuation.

È quindi possibile utilizzare un elemento WorkContinuation per aggiungere istanze OneTimeWorkRequest dipendenti utilizzando then(OneTimeWorkRequest) o then(List<OneTimeWorkRequest>) .

Ogni chiamata di WorkContinuation.then(...) restituisce una nuova istanza di WorkContinuation. Se aggiungi List istanze su OneTimeWorkRequest, queste richieste possono potenzialmente essere eseguite in parallelo.

Infine, puoi utilizzare il metodo WorkContinuation.enqueue() per enqueue() la tua catena di WorkContinuation.

Vediamo un esempio. In questo esempio, sono configurati 3 diversi job worker per l'esecuzione (potenzialmente in parallelo). I risultati di questi worker vengono quindi uniti e passati a un job Worker memorizzazione nella cache. Infine, l'output del job viene passato a un worker di caricamento, che carica i risultati su un server remoto.

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

Fusioni di input

Quando concateni le istanze OneTimeWorkRequest, l'output delle richieste di lavoro padre viene trasmesso come input alle istanze figlio. Quindi, nell'esempio precedente, gli output di plantName1, plantName2 e plantName3 verrebbero passati come input alla richiesta cache.

Per gestire gli input di più richieste di lavoro principali, WorkManager utilizza InputMerger.

WorkManager fornisce due diversi tipi di InputMerger:

  • OverwritingInputMerger tenta di aggiungere all'output tutte le chiavi di tutti gli input. In caso di conflitti, le chiavi impostate in precedenza vengono sovrascritte.

  • ArrayCreatingInputMerger tenta di unire gli input, creando array quando necessario.

Se hai un caso d'uso più specifico, puoi scriverne uno personalizzato sottoclassificando InputMerger.

SovrascritturaInputMerger

OverwritingInputMerger è il metodo di unione predefinito. In caso di conflitti di chiave nell'unione, l'ultimo valore di una chiave sovrascriverà eventuali versioni precedenti nei dati di output risultanti.

Ad esempio, se gli input dell'impianto hanno ciascuno una chiave corrispondente ai rispettivi nomi delle variabili ("plantName1", "plantName2" e "plantName3"), i dati passati al worker cache avranno tre coppie chiave-valore.

Diagramma che mostra tre job che passano diversi output al job successivo nella catena. Poiché i tre output hanno tutti chiavi diverse, il job successivo riceve tre coppie chiave/valore.

In caso di conflitto, l'ultimo worker a completare "wins" e il relativo valore viene passato a cache.

Diagramma che mostra tre job che passano gli output al job successivo nella catena. In questo caso, due di questi job producono output con la stessa chiave. Di conseguenza, il job successivo riceve due coppie chiave/valore, con uno degli output in conflitto eliminato.

Poiché le richieste di lavoro vengono eseguite in parallelo, non hai garanzie in merito all'ordine in cui vengono eseguite. Nell'esempio precedente, plantName1 potrebbe contenere "tulip" o "elm", a seconda dell'ultimo valore scritto. Se si verifica un conflitto tra le chiavi e devi conservare tutti i dati di output in una fusione, ArrayCreatingInputMerger potrebbe essere un'opzione migliore.

ArrayCreatingInputMerger

Nell'esempio precedente, considerando che vogliamo conservare gli output di tutti i worker dei nomi degli impianti, dobbiamo utilizzare un 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 accoppia ogni chiave a un array. Se ogni chiave è univoca, il risultato è una serie di array di un elemento.

Diagramma che mostra tre job che passano diversi output al job successivo nella catena. Al job successivo vengono passati tre array, uno per ciascuna delle chiavi di output. Ogni array ha un singolo membro.

In caso di conflitti di chiavi, i valori corrispondenti vengono raggruppati in un array.

Diagramma che mostra tre job che passano gli output al job successivo nella catena. In questo caso, due di questi job producono output con la stessa chiave. Al job successivo vengono passati due array, uno per ogni chiave. Uno di questi array ha due membri, poiché erano presenti due output con quella chiave.

Concatenamento e stati di lavoro

Le catene di OneTimeWorkRequest vengono eseguite in sequenza purché il loro lavoro venga completato correttamente (ovvero, restituisce un Result.success()). Le richieste di lavoro potrebbero non riuscire o essere annullate durante l'esecuzione, con un effetto downstream sulle richieste di lavoro dipendenti.

Quando il primo OneTimeWorkRequest viene accodato in una catena di richieste di lavoro, tutte le richieste di lavoro successive vengono bloccate fino a quando il lavoro della prima richiesta di lavoro non viene completato.

Diagramma che mostra una catena di job. Il primo job viene accodato e tutti i job successivi vengono bloccati fino al termine del primo.

Una volta accodato e soddisfatti tutti i vincoli di lavoro, inizia l'esecuzione della prima richiesta di lavoro. Se il lavoro viene completato correttamente nell'elemento principale OneTimeWorkRequest o List<OneTimeWorkRequest> (ovvero restituisce Result.success()), il gruppo successivo di richieste di lavoro dipendenti sarà accodato.

Diagramma che mostra una catena di job. Il primo lavoro è riuscito e i suoi due immediatamente successori sono in coda. I job rimanenti sono bloccati per il completamento dei job precedenti.

Finché ogni richiesta di lavoro viene completata correttamente, questo stesso pattern propaga il resto delle richieste della catena di lavoro fino al completamento di tutto il lavoro nella catena. Sebbene questo sia il caso più semplice e spesso preferito, gli stati di errore sono altrettanto importanti da gestire.

Quando si verifica un errore mentre un worker elabora la tua richiesta di lavoro, puoi ritentare la richiesta in base a un criterio di backoff da te definito. Se ritenterai una richiesta che fa parte di una catena, verrà tentata solo quella richiesta con i dati di input che le sono stati forniti. Qualsiasi lavoro in esecuzione in parallelo non subirà modifiche.

Diagramma che mostra una catena di job. Uno dei job non è riuscito, ma aveva un criterio di backoff definito. Il job verrà eseguito nuovamente una volta trascorso il periodo di tempo appropriato. I job che seguono nella catena vengono bloccati finché non viene eseguito correttamente.

Per saperne di più sulla definizione di strategie personalizzate per i nuovi tentativi, consulta Criterio di ripetizione e backoff.

Se il criterio relativo ai nuovi tentativi non è definito o è esaurito oppure se raggiungi uno stato in cui un OneTimeWorkRequest restituisce Result.failure(), la richiesta di lavoro e tutte le richieste di lavoro dipendenti vengono contrassegnate come FAILED..

Diagramma che mostra una catena di job. Un job non è riuscito e non è possibile riprovare. Di conseguenza, anche tutti i job successivi nella catena avranno esito negativo.

La stessa logica si applica quando un OneTimeWorkRequest viene annullato. Anche tutte le richieste di lavoro dipendenti sono contrassegnate con CANCELLED e il loro lavoro non verrà eseguito.

Diagramma che mostra una catena di job. Un job è stato annullato. Di conseguenza, vengono annullati anche tutti i job successivi nella catena.

Tieni presente che se dovessi aggiungere altre richieste di lavoro a una catena che non è andata a buon fine o che ha annullato richieste di lavoro, anche la richiesta di lavoro appena aggiunta verrà contrassegnata rispettivamente con FAILED o CANCELLED. Se vuoi estendere il lavoro di una catena esistente, consulta APPEND_OR_REPLACE in existingWorkPolicy.

Quando si creano catene di richieste di lavoro, le richieste di lavoro dipendenti devono definire criteri di ripetizione per garantire che il lavoro venga sempre completato in modo tempestivo. Le richieste di lavoro non riuscite potrebbero causare catene incomplete e/o stati imprevisti.

Per ulteriori informazioni, consulta Annullamento e arresto di lavoro.