Travaux d'arrière-plan au printemps avec JobRunr

1. Vue d'ensemble

Dans ce didacticiel, nous allons examiner la planification et le traitement des tâches en arrière-plan distribuées en Java à l'aide de JobRunr et l'intégrer à Spring.

2. À propos de JobRunr

JobRunr est une bibliothèque que nous pouvons intégrer dans notre application et qui nous permet de planifier des jobs d'arrière-plan à l'aide d'un lambda Java 8. Nous pouvons utiliser n'importe quelle méthode existante de nos services Spring pour créer un travail sans avoir besoin d'implémenter une interface. Un travail peut être un processus court ou long, et il sera automatiquement déchargé vers un thread d'arrière-plan afin que la requête Web actuelle ne soit pas bloquée.

Pour faire son travail, JobRunr analyse le lambda Java 8. Il le sérialise en tant que JSON et le stocke dans une base de données relationnelle ou dans un magasin de données NoSQL.

3. Caractéristiques de JobRunr

Si nous constatons que nous produisons trop de tâches en arrière-plan et que notre serveur ne peut pas faire face à la charge, nous pouvons facilement évoluer horizontalement en ajoutant simplement des instances supplémentaires de notre application. JobRunr partagera automatiquement la charge et distribuera tous les travaux sur les différentes instances de notre application.

Il contient également une fonction de nouvelle tentative automatique avec une stratégie de back-off exponentielle pour les travaux ayant échoué. Il existe également un tableau de bord intégré qui nous permet de surveiller tous les travaux. JobRunr est auto-entretenu - les travaux réussis seront automatiquement supprimés après une durée configurable, il n'est donc pas nécessaire d'effectuer un nettoyage manuel du stockage.

4. Configuration

Par souci de simplicité, nous utiliserons un magasin de données en mémoire pour stocker toutes les informations liées au travail.

4.1. Configuration Maven

Passons directement au code Java. Mais avant cela, nous devons déclarer la dépendance Maven suivante dans notre fichier pom.xml :

 org.jobrunr jobrunr-spring-boot-starter 1.1.0 

4.2. Intégration de printemps

Avant de passer directement à la création de tâches en arrière-plan, nous devons initialiser JobRunr. Comme nous utilisons la dépendance jobrunr-spring-boot-starter , c'est facile. Il suffit d'ajouter quelques propriétés à l' application.properties :

org.jobrunr.background-job-server.enabled=true org.jobrunr.dashboard.enabled=true

La première propriété indique à JobRunr que nous voulons démarrer une instance d'un BackgroundJobServer qui est responsable du traitement des travaux. La deuxième propriété indique à JobRunr de démarrer le tableau de bord intégré.

Par défaut, le jobrunr-spring-boot-starter essaiera d'utiliser votre DataSource existante dans le cas d'une base de données relationnelle pour stocker toutes les informations liées au travail.

Cependant, puisque nous allons utiliser un magasin de données en mémoire, nous devons fournir un bean StorageProvider :

@Bean public StorageProvider storageProvider(JobMapper jobMapper) { InMemoryStorageProvider storageProvider = new InMemoryStorageProvider(); storageProvider.setJobMapper(jobMapper); return storageProvider; }

5. Utilisation

Voyons maintenant comment créer et planifier des tâches d'arrière-plan au printemps à l'aide de JobRunr.

5.1. Injecter les dépendances

Lorsque nous voulons créer des emplois, nous devons injecter le JobScheduler et notre service Spring existant contenant la méthode pour laquelle nous voulons créer des emplois, dans ce cas, le SampleJobService :

@Inject private JobScheduler jobScheduler; @Inject private SampleJobService sampleJobService;

La classe JobScheduler de JobRunr nous permet de mettre en file d'attente ou de planifier de nouveaux travaux en arrière-plan.

Le SampleJobService peut être l'un de nos services Spring existants contenant une méthode qui peut prendre trop de temps à gérer dans une requête Web. Il peut également s'agir d'une méthode qui appelle d'autres services externes auxquels nous voulons ajouter de la résilience, car JobRunr réessayera la méthode si une exception se produit.

5.2. Créer des tâches d'incendie et d'oubli

Maintenant que nous avons nos dépendances, nous pouvons créer des tâches d'incendie et d'oubli en utilisant la méthode de mise en file d'attente :

jobScheduler.enqueue(() -> sampleJobService.executeSampleJob());

Les jobs peuvent avoir des paramètres, comme n'importe quel autre lambda:

jobScheduler.enqueue(() -> sampleJobService.executeSampleJob("some string"));

Cette ligne garantit que le lambda - y compris le type, la méthode et les arguments - est sérialisé en tant que JSON dans le stockage persistant (un SGBDR comme Oracle, Postgres, MySql et MariaDB ou une base de données NoSQL).

Un pool de threads de travail dédié s'exécutant dans tous les différents BackgroundJobServer s exécutera alors ces travaux d'arrière-plan en file d'attente dès que possible, selon le principe du premier entré premier sorti. JobRunr garantit l'exécution de votre travail par un seul travailleur au moyen d'un verrouillage optimiste.

5.3. Planification des travaux dans le futur

Nous pouvons également planifier des travaux à l'avenir en utilisant la méthode de planification :

jobScheduler.schedule(() -> sampleJobService.executeSampleJob(), LocalDateTime.now().plusHours(5));

5.4. Planifier des travaux de manière récurrente

Si nous voulons avoir des tâches récurrentes, nous devons utiliser la méthode scheduleRecurrently :

jobScheduler.scheduleRecurrently(() -> sampleJobService.executeSampleJob(), Cron.hourly());

5.5. Annoter avec l' annotation @Job

To control all aspects of a job, we can annotate our service method with the @Job annotation. This allows setting the display name in the dashboard and configuring the number of retries in case a job fails.

@Job(name = "The sample job with variable %0", retries = 2) public void executeSampleJob(String variable) { ... }

We can even use variables that are passed to our job in the display name by means of the String.format() syntax.

If we have very specific use cases where we would want to retry a specific job only on a certain exception, we can write our own ElectStateFilter where we have access to the Job and full control on how to proceed.

6. Dashboard

JobRunr comes with a built-in dashboard that allows us to monitor our jobs. We can find it at //localhost:8000 and inspect all the jobs, including all recurring jobs and an estimation of how long it will take until all the enqueued jobs are processed:

Bad things can happen, for example, an SSL certificate expired, or a disk is full. JobRunr, by default, will reschedule the background job with an exponential back-off policy. If the background job continues to fail ten times, only then will it go to the Failed state. You can then decide to re-queue the failed job when the root cause has been solved.

All of this is visible in the dashboard, including each retry with the exact error message and the complete stack trace of why a job failed:

7. Conclusion

Dans cet article, nous avons construit notre premier planificateur de base en utilisant JobRunr avec le jobrunr-spring-boot-starter . Le principal à retenir de ce didacticiel est que nous avons pu créer un travail avec une seule ligne de code et sans aucune configuration basée sur XML ou la nécessité d'implémenter une interface.

Le code source complet de l'exemple est disponible à l'adresse over sur GitHub.