Enchaînement de travaux

WorkManager vous permet de créer et de mettre en file d'attente une chaîne de travail qui reprend plusieurs tâches dépendantes et définit l'ordre dans lequel elles doivent s'exécuter. Cette fonctionnalité est particulièrement utile lorsque vous devez exécuter plusieurs tâches dans un ordre précis.

Pour créer une chaîne de travail, vous pouvez utiliser WorkManager.beginWith(OneTimeWorkRequest) ou WorkManager.beginWith(List<OneTimeWorkRequest>), qui renvoient chacun une instance de WorkContinuation.

Une WorkContinuation permet ensuite d'ajouter des instances OneTimeWorkRequest dépendantes à l'aide de then(OneTimeWorkRequest) ou de then(List<OneTimeWorkRequest>).

Chaque appel de WorkContinuation.then(...) renvoie une nouvelle instance de WorkContinuation. Si vous ajoutez une List d'instances OneTimeWorkRequest, ces requêtes peuvent éventuellement s'exécuter en parallèle.

Enfin, vous pouvez utiliser la méthode WorkContinuation.enqueue() pour enqueue() votre chaîne de WorkContinuation.

Prenons un exemple. Imaginons trois tâches Worker différentes configurées pour s'exécuter (potentiellement en parallèle). Les résultats de ces Workers sont ensuite joints et transmis à une tâche de mise en cache Worker. Enfin, le résultat de cette tâche est transmis à un Worker d'importation, qui importe les résultats vers un serveur distant.

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

Fusionneurs d'entrées

Lorsque vous associez des instances OneTimeWorkRequest, la sortie des requêtes de travail parent est transmise en entrée aux enfants. Ainsi, dans l'exemple ci-dessus, les sorties de plantName1, plantName2 et plantName3 seraient transmises en tant qu'entrées à la requête cache.

Pour gérer les entrées provenant de plusieurs requêtes de travail parent, WorkManager utilise InputMerger.

WorkManager fournit deux types d'InputMerger différents :

  • OverwritingInputMerger tente d'ajouter toutes les clés de toutes les entrées à la sortie. En cas de conflit, il remplace les clés définies précédemment.

  • ArrayCreatingInputMerger tente de fusionner les entrées en créant, si nécessaire, des tableaux.

En cas d'utilisation plus spécifique, vous pouvez écrire le vôtre en sous-classant InputMerger.

OverwritingInputMerger

OverwritingInputMerger est la méthode de fusion par défaut. En cas de conflit de clés dans la fusion, la dernière valeur d'une clé écrase toutes les versions précédentes dans les données de sortie obtenues.

Par exemple, si les entrées de la plante disposent chacune d'une clé correspondant à leurs noms de variables respectifs ("plantName1", "plantName2" et "plantName3"), les données transmises au nœud de calcul de cache auront trois paires clé/valeur.

Schéma illustrant trois tâches transmettant des sorties différentes à la tâche suivante de la chaîne. Les trois sorties ayant toutes des clés différentes, la tâche suivante reçoit trois paires clé/valeur.

En cas de conflit, le dernier nœud de calcul à s'achever "gagne" et sa valeur est transmise à cache.

Schéma illustrant trois tâches transmettant des sorties à la tâche suivante de la chaîne. Deux de ces tâches produisent alors des sorties avec la même clé. La tâche suivante reçoit donc deux paires clé/valeur, et l&#39;une des sorties en conflit est supprimée.

Étant donné que vos requêtes de travail sont exécutées en parallèle, vous n'avez aucune garantie de l'ordre dans lequel elles s'exécutent. Dans l'exemple ci-dessus, plantName1 pourrait contenir la valeur "tulip" ou "elm", en fonction de la valeur écrite en dernier. Si vous avez un risque de conflit de clés et que vous devez conserver toutes les données de sortie dans une fusion, ArrayCreatingInputMerger peut être une meilleure option.

ArrayCreatingInputMerger

Pour l'exemple ci-dessus, il faut utiliser un ArrayCreatingInputMerger, car nous voulons conserver les sorties de tous les nœuds de calcul des noms de plantes.

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 associe chaque clé à un tableau. Si chacune des clés est unique, vous obtenez une série de tableaux à un élément.

Schéma illustrant trois tâches transmettant des sorties différentes à la tâche suivante de la chaîne. La tâche suivante reçoit trois tableaux, un pour chacune des clés de sortie. Chaque tableau ne comporte qu&#39;un seul membre.

En cas de conflit de clés, toutes les valeurs correspondantes sont regroupées dans un tableau.

Schéma illustrant trois tâches transmettant des sorties à la tâche suivante de la chaîne. Deux de ces tâches produisent alors des sorties avec la même clé. La tâche suivante reçoit deux tableaux, un pour chaque clé. L&#39;un de ces tableaux contient deux membres, car il existe deux sorties avec cette clé.

Statuts de chaînes et de tâches

Les chaînes de OneTimeWorkRequest s'exécutent de manière séquentielle tant que leur travail se termine correctement (c'est-à-dire qu'elles renvoient un Result.success()). Les requêtes de tâches peuvent échouer ou être annulées pendant l'exécution, ce qui a des effets en aval sur les requêtes de tâches dépendantes.

Lorsque la première requête OneTimeWorkRequest est mise en file d'attente dans une chaîne de requêtes de tâches, toutes les requêtes suivantes sont bloquées jusqu'à ce que la première requête de tâche soit terminée.

Schéma représentant une chaîne de tâches. La première tâche est mise en file d&#39;attente et toutes les tâches suivantes sont bloquées jusqu&#39;à la fin de la première.

Une fois en file d'attente et toutes les contraintes de travail satisfaites, la première requête de tâche s'exécute. Si le travail est terminé à la racine OneTimeWorkRequest ou List<OneTimeWorkRequest> (c'est-à-dire qu'il renvoie Result.success()), l'ensemble de requêtes de tâches suivant est mis en file d'attente.

Schéma représentant une chaîne de tâches. La première tâche a réussi et ses deux successeurs immédiats sont mis en file d&#39;attente. Les tâches restantes sont bloquées tant que la tâche précédente n&#39;est pas terminée.

Tant que chaque requête de tâche se termine correctement, ce même schéma se propage dans le reste de votre chaîne de requêtes de tâches jusqu'à ce que toutes les tâches de la chaîne soient terminées. Bien que ce soit le cas le plus simple et le plus souvent privilégié, les états d'erreur sont tout aussi importants à gérer.

Lorsqu'une erreur se produit pendant qu'un nœud de calcul traite votre requête de tâche, vous pouvez la relancer en fonction d'une règle d'intervalle entre les tentatives que vous définissez. Si vous relancez une requête faisant partie d'une chaîne, seule cette requête sera relancée avec les données d'entrée qui lui sont fournies. Tout travail exécuté en parallèle ne sera pas affecté.

Schéma représentant une chaîne de tâches. L&#39;une des tâches a échoué, mais une règle d&#39;intervalle entre les tentatives était définie. Cette tâche sera exécutée à nouveau une fois cet intervalle écoulé. Les tâches qui suivent dans la chaîne sont bloquées jusqu&#39;à la réussite de son exécution.

Pour en savoir plus sur la définition de règles de nouvelle tentative personnalisées, consultez les Règles concernant les nouvelles tentatives et l'intervalle entre les tentatives.

Si aucune règle de nouvelle tentative n'est définie, si elle est obsolète ou si vous atteignez un état dans lequel une OneTimeWorkRequest renvoie Result.failure(), cette requête de tâche et toutes les requêtes de tâches dépendantes sont marquées comme FAILED..

Schéma représentant une chaîne de tâches. Une tâche a échoué et ne peut être relancée. Toutes les tâches qui suivent dans la chaîne échouent donc également.

La même logique s'applique lorsqu'une OneTimeWorkRequest est annulée. Toutes les requêtes de tâches dépendantes sont également marquées CANCELLED et leur tâche n'est pas exécutée.

Schéma représentant une chaîne de tâches. Une tâche a été annulée. Toutes les tâches situées plus loin dans cette chaîne sont donc également annulées.

Notez que si vous ajoutez des requêtes de tâches supplémentaires à une chaîne ayant échoué ou ayant des requêtes de tâches annulées, votre nouvelle requête de tâche sera respectivement marquée comme FAILED ou CANCELLED. Si vous souhaitez étendre la tâche d'une chaîne existante, consultez APPEND_OR_REPLACE dans l'ExistingWorkPolicy.

Lorsque vous créez des chaînes de requêtes de tâches dépendantes, celles-ci doivent définir des règles de nouvelle tentative pour garantir que la tâche est toujours terminée à temps. Les requêtes de tâches ayant échoué peuvent entraîner des chaînes incomplètes et/ou un état inattendu.

Pour en savoir plus, consultez Annuler et arrêter une tâche.