Création de temporisateurs à l'aide du service de temporisation EJB pour les beans enterprise
Vous pouvez utiliser les beans enterprise afin de profiter du service de temporisation EJB pour planifier des événements basés sur le temps.
Pourquoi et quand exécuter cette tâche
Dans le cadre de la spécification EJB 3.1, vous pouvez créer des temporisateurs EJB non persistants. Ce produit prend également en charge l'API étendue TimerService pour la création programmée de temporisateurs. En outre, le conteneur EJB peut être configuré de façon à créer automatiquement un temporisateur au démarrage de l'application.
WebSphere Application Server implémente le service de temporisation EJB (Enterprise JavaBeans). Selon les besoins de votre activité, vous pouvez utiliser des temporisateurs persistants ou non persistants. Les temporisateurs persistants conviennent pour un événement périodique qui exige obligatoirement la présence d'un temporisateur au delà du cycle de vie du serveur. Les temporisateurs persistants déjà lancés démarrent automatiquement quand le serveur démarre et perdurent au delà des arrêts et des redémarrages du serveur. Par exemple, vous pouvez utiliser un temporisateur persistant pour démarrer une application système ou envoyer une notification de statut sur l'expiration d'un temporisateur. Les temporisateurs non persistants sont utiles dans des situations non cruciales où les actions du temporisateur sont ignorées ou répétées sans impacts négatifs sur l'activité, par exemple le relevé d'une température.
Vous pouvez créer des temporisateurs par programmation. Vous pouvez également créer des temporisateurs automatiquement en utilisant l'annotation @Schedule dans la classe de bean ou l'élément de temporisateur dans le descripteur de déploiement ejb-jar.xml. En créant des temporisateurs automatiquement, vous pouvez planifier un temporisateur, sans dépendre du bean enterprise pour le démarrage programmé d'une méthode de création de service de temporisation EJB.
- temporisateurs persistants
-
Les temporisateurs persistants sont mis en oeuvre en tant que tâche du service de planification. Par défaut, une instance de planificateur interne ou pré-configurée est utilisée pour gérer ces tâches et elles sont conservées dans une base de données Apache Derby associée au processus serveur.
Vous pouvez procéder à des personnalisations de base de l'instance de planificateur interne. Pour plus d'informations sur la personnalisation de l'instance de planificateur, voir la rubrique relative à la configuration d'un service de temporisation.
La création et l'annulation de temporisateurs sont des opérations transactionnelles et persistantes. Si un temporisateur est créé dans le cadre d'une transaction et que cette transaction est ensuite annulée, la création du temporisateur est également annulée. Les mêmes règles s'appliquent à l'annulation d'un temporisateur. Les temporisateurs démarrés antérieurement sont conservés après les arrêts et redémarrages successifs du serveur d'applications.
- Temporisateurs non persistants
-
EJB 3.1 améliore le service de temporisation EJB en permettant d'activer des temporisateurs EJB non persistants en plus des temporisateurs persistants. Le mode opératoire et la sémantique des temporisateurs non persistants sont pour une bonne part similaires à ceux des temporisateurs persistants, mais sans le poids des magasins de données. Les temporisateurs non persistants ont un cycle de vie différent de celui des temporisateurs persistants. Alors que les temporisateurs persistants sont conservés après les arrêts et redémarrages successifs du serveur d'applications, les temporisateurs non persistants ne sont actifs que pendant l'activité du serveur d'applications. Au contraire des temporisateurs persistants, il n'existe pas de commande pour rechercher ou annuler les temporisateurs non persistants. Les temporisateurs non persistant sont annulés quand le serveur d'applications est arrêté ou devient inactif.
Comme pour les temporisateurs persistants, la création et l'annulation des temporisateurs non persistants sont des opérations transactionnelles. Si un temporisateur est créé dans le cadre d'une transaction et que cette transaction est ensuite annulée, la création du temporisateur est également annulée. Les mêmes règles s'appliquent à l'annulation d'un temporisateur.
Les temporisateurs non persistants peuvent être configurés de façon à partager un pool d'unités d'exécution avec des temporisateurs persistants, ou de façon à disposer d'un pool d'unités d'exécution unique non partagé avec les temporisateurs persistants.
- Temporisateurs créés par programmation
-
Un temporisateur persistant créé de façon programmée est conservé après les arrêts et redémarrages successifs du serveur d'applications, sauf s'il est annulé. Il est de la responsabilité du code de l'application ou de l'administrateur système de supprimer un temporisateurs créé par programmation devenu inutile.
Pour créer par programmation un temporisateur associé à votre bean enterprise, le bean appelle la méthode getTimerService() sur l'instance de contexte applicable pour obtenir une référence pour l'objet TimerService. Le bean appelle également une des méthodes TimerService, par exemple createTimer, pour spécifier le temporisateur pour le bean. Cette instance de temporisateur est désormais associée à votre bean. Les méthodes TimerService sont décrites dans la spécification EJB 3.1. Vous pouvez désormais transmettre l'instance Timer à un autre code Java™ en tant qu'objet local. Une fois que le code Java a obtenu l'instance Timer, il peut utiliser toutes les méthodes définies par l'interface javax.ejb.Timer, par exemple la méthode cancel() ou getTimeRemaining().
Dans un environnement en clusters, un temporisateur persistant créé à l'aide d'un programme peut s'exécuter dans n'importe quel membre de cluster. Par contre, un temporisateur non persistant créé à l'aide d'un programme ne peut s'exécuter que dans la machine JVM où il a été créé.
- Temporisateurs créés automatiquement
- La spécification EJB 3.1 améliore le service de temporisation EJB en permettant d'activer la création automatique d'un temporisateur au démarrage de l'application, sans dépendre d'un bean pour le démarrage programmé d'une méthode de création de temporisateur du service de temporisation. Utilisez l'annotation @Schedule ou l'élément de descripteur de déploiement timeout-method pour créer automatiquement des temporisateurs. Les temporisateurs crées automatiquement sont créés par le conteneur suite au déploiement d'une application.
Eviter les incidents: La commande CancelEJBTimers annule également les temporisateurs créés automatiquement. Lorsque des temporisateurs créés automatiquement sont annulés, la seule manière de les recréer est de désinstaller, puis réinstaller l'application.gotcha
- Temporisateurs dans un environnement en cluster
-
Dans un environnement en cluster, un temporisateur persistant s'exécute dans un seul membre de cluster, qui n'est pas forcément celui dans lequel il a été créé. Un temporisateur non persistant s'exécute dans chaque membre de cluster dans lequel il a été créé - les temporisateurs persistants automatiques s'exécutent dans tous les membres de cluster contenant le bean EJB.
Les temporisateurs persistants automatiques sont supprimés de leur stockage persistant lorsque le module ou l'application qui les contient est désinstallé. Vous ne devez donc pas mettre à jour des applications qui utilisent des temporisateurs persistant automatiques avec la fonction Déployer la mise à jour. Cette fonction désinstalle et réinstalle l'application pendant que le cluster est opérationnel, ce qui peut provoquer des défaillances dans les cas suivants :
- Si un temporisateur s'exécutant dans un autre membre de cluster est activé après la suppression de l'entrée de base de données et avant qu'elle soit recréée, le temporisateur échoue. Dans ce cas, une exception com.ibm.websphere.scheduler.TaskPending est enregistrée dans l'outil FFDC (First Failure Data Capture), avec le message SCHD0057W indiquant que les informations sur la tâche dans la base de données ont été modifiées ou annulées.
- Si le temporisateur est actif dans un membre qui n'a pas été mis à jour après que les données du temporisateur dans la base de données l'ont été, et si les nouvelles données du temporisateur sont incompatibles avec l'ancien code de l'application toujours en cours d'exécution dans le membre de cluster, le temporisateur peut échouer ou provoquer d'autres défaillances.
Lorsque vous utilisez le serveur proxy dans le produit, ne définissez pas de planificateur à l'échelle de la cellule si ce planificateur est configuré comme celui à utiliser pour le service de temporisateurs EJB. Faute de quoi, les temporisateurs persistants ne pourront pas fonctionner. Cela peut arriver si le serveur proxy obtient le bail du planificateur. Comme aucune application n'est exécutée dans le serveur proxy, il n'y a pas de code d'application pour traiter les événements de temporisateur envoyés par le planificateur.
- Nouvelles tentatives et exécutions manquées
-
Si vous utilisez des temporisateurs EJB, vous devez comprendre les concepts d'échec, de nouvelle tentative et d'exécution manquée.
- Un échec correspond à une exécution qui a été tentée, mais qui n'a pas abouti à la fin du délai d'attente.
- Une nouvelle tentative est une tentative supplémentaire d'exécuter avec succès une opération qui a précédemment échoué à la fin de son délai d'attente.
- Une exécution manquée est une exécution qui aurait dû être tentée, mais qui ne l'a pas été parce que le serveur était indisponible, ou occupé à tenter de réexécuter une opération ayant précédemment échoué.
Le comportement vis-à-vis des nouvelles tentatives reflète :- Le nombre de tentatives supplémentaires effectuées par le serveur en cas d'échec à la fin du délai d'attente
- L'intervalle entre ces tentatives
Le comportement vis-à-vis des exécutions manquées reflète :- Si le serveur lance, ou non, les tentatives d'exécution qui ont été manquées
- Si les exécutions manquées sont tentées, le moment auquel cela se produit
- L'intervalle entre ces tentatives
Tableau 1. Comportement des nouvelles tentatives et des exécutions manquées. Comportement des nouvelles tentatives et des exécutions manquées pour les temporisateurs persistants et non persistants. Caractéristiques Comportement par défaut Configurable Nombre de nouvelles tentatives Autant que nécessaire jusqu'à ce que l'exécution aboutisse. Les temporisateurs persistants sont temporairement désactivés si leur seuil d'échec de planification est atteint sur un serveur. Pour plus d'informations, voir la rubrique sur l'arrêt des tâches ayant échoué.
Oui, pour les temporisateurs non persistants Intervalle entre les nouvelles tentatives La première nouvelle tentative est immédiate. Les tentatives suivantes sont lancées selon l'intervalle d'interrogation configuré dans le planificateur pour les temporisateurs persistants, et selon l'intervalle entre les nouvelles tentatives pour les temporisateurs non persistants.
Yes Reprise des exécutions manquées Toutes les exécutions manquées sont reprises. Non Moment de la reprise des exécutions manquées Les temporisateurs persistants et non persistants reprennent les exécutions manquées à l'arrêt des tentatives bloquantes. En outre, les temporisateurs persistants reprennent les exécutions au redémarrage du serveur indisponible. Non Exécution suivante, après que les nouvelles tentatives ont réussi et que les exécutions manquées ont été reprises A l'heure d'origine planifiée suivante. Non Les caractéristiques qui peuvent être configurées le sont dans l'instance du planificateur pour les temporisateurs persistants, et dans la configuration du temporisateur non persistant pour ce dernier type de temporisateur.
Les scénarios suivants illustrent la façon dont le comportement des nouvelles tentatives et des exécutions manquées influence les exécutions des temporisateurs persistants et non persistants.
Scénario mettant en oeuvre un temporisateur persistant :
Un temporisateur persistant est créé et configuré pour s'exécuter d'abord à 10:00, puis à chaque heure suivante. Le planificateur qui prend en charge le temporisateur est configuré avec un intervalle d'interrogation de 30 secondes.
Le temporisateur tente de s'exécuter à 10:00 et échoue parce qu'une base de données est indisponible. Le temporisateur effectue immédiatement une nouvelle tentative, puis une autre toutes les 30 secondes lorsque le planificateur est interrogé, et continue à échouer jusqu'à 12:30. A ce moment, une tentative aboutit car la base de données est de nouveau en ligne, et donc le serveur arrête les nouvelles tentatives qu'il effectuait à la suite d'un échec.
Maintenant, le serveur commence à se consacrer aux exécutions manquées. Il lance la tentative d'exécution qui aurait dû avoir lieu à 11:00, et celle-ci aboutit à 12:31. Lorsque le planificateur est interrogé à nouveau 30 secondes plus tard, le serveur lance la tentative d'exécution qui aurait dû avoir lieu à 12:00, et qui aboutit à 12:32. Le serveur est à jour, et l'exécution suivante a lieu à l'heure planifiée à l'origine, 13:00, et non une heure après la dernière exécution réussie, ce qui aurait donné 13:32. A partir de ce moment le planning d'origine est respecté. Il n'est pas mis à jour en fonction de l'heure de la dernière exécution réussie.
Scénario mettant en oeuvre un temporisateur non persistant :
Un temporisateur non persistant est créé et configuré pour s'exécuter d'abord à 10:00, puis à chaque heure suivante. Ce temporisateur non persistant est configuré avec un nombre de nouvelles tentatives de 5, et un intervalle de 30 minutes entre les nouvelles tentatives.
Le temporisateur tente de s'exécuter à 10:00 et échoue parce qu'une base de données est indisponible. Le temporisateur effectue immédiatement une nouvelle tentative, et échoue à nouveau. Ensuite, après avoir exécuté immédiatement la nouvelle tentative initiale, le serveur attend pendant la durée de l'intervalle de 30 minutes configuré entre les nouvelles tentatives. De nouvelles tentatives ont lieu à 10:30 et 11:00, et les deux échouent. Finalement, la quatrième tentative se produit à 11:30 et réussit car la base de données est à nouveau en ligne.
Maintenant, le serveur commence à se consacrer aux exécutions manquées. L'exécution qui était planifiée à l'origine à 11:00 est effectuée immédiatement, et réussit à 11:31. Le serveur est désormais à jour, et l'exécution suivante a lieu à l'heure planifiée à l'origine, 12:00, et non une heure après la dernière exécution réussie, ce qui aurait donné 12:32.
- Comportement des méthodes getNextTimeout et getTimeRemaining
-
Pour les temporisateurs persistants et non persistants, la méthode Timer.getNextTimeout renvoie un objet java.util.Date qui indique l'heure de la prochaine exécution planifiée. Lorsque la méthode getNextTimeout est appelée pour un temporisateur basé sur un intervalle ou un agenda, elle renvoie la prochaine heure planifiée ; dans le cas des temporisateurs basés sur un agenda pour lesquels aucune exécution à venir n'est prévue, la méthode revoie l'exception NoMoreTimeoutsException, comme le demande la spécification EJB 3.1. Lorsque la méthode getNextTimeout est appelée à partir d'une méthode de rappel d'exécution pour un temporisateur à action unique, elle renvoie l'heure planifiée d'origine. En cas d'échec d'une méthode de rappel d'exécution, si de nouvelles tentatives sont effectuées, la méthode getNextTimeout continue à renvoyer l'heure planifiée d'origine, comme si l'exécution en échec n'avait pas eu lieu. Dans tous les cas, la méthode Timer.getTimeRemaining renvoie la différence en millisecondes entre la valeur getNextTimeout renvoyée et l'heure système en cours, ce qui peut produire un nombre négatif si l'heure d'exécution planifiée est passée.
- Comportement de l'héritage des temporisateurs créés automatiquement
-
Les méthodes de temporisateur automatique dans une hiérarchie de classes de beans engendrent la création de plusieurs temporisateurs. Le nombre de temporisateurs associés à une méthode de temporisateur n'est pas déterminé par le nombre d'occurrences de la méthode dans le code source. En revanche, le nombre de temporisateurs associés à une méthode de temporisateur est déterminé par le nombre de beans disposant de la visibilité sur cette méthode. Exemple :
@Stateless public class Abean { @Schedule(hour=”1”) public void timerMethod1() @Stateless public class Bbean extends Abean { @Schedule(hour=”2”) public void timerMethod2() @Stateless public class Cbean extends Bbean { @Schedule(hour=”2”) public void timerMethod2()
Dans la hiérarchie de classes de beans précédente, trois temporisateurs automatiques avec la méthode de rappel Abean.timerMethod1 sont créés, un pour chaque instance disposant de la visibilité sur la méthode. Un temporisateur avec la méthode de rappel Bbean.timerMethod2 est créé, et puisque cette méthode est neutralisée par le bean Cbean, seul un temporisateur avec la méthode de rappel Cbean.timerMethod2 est créé.
Dans l'exemple précédent, lorsque le bean Abean est traité par le conteneur, un temporisateur automatique unique est créé, avec la méthode de rappel Abean.timerMethod1.
Lorsque le bean Bbean est traité par le conteneur, un temporisateur automatique est créé avec la méthode de rappel Bbean.timerMethod2, et un autre temporisateur est créé avec la méthode de rappel Abean.timerMethod1.
Lorsque le bean Cbean est traité par le conteneur, un temporisateur automatique est créé avec la méthode de rappel CBean.timerMethod2. Un autre temporisateur automatique est créé avec la méthode de rappel Abean.timerMethod1. Aucun temporisateur pour Bbean.timerMethod2 n'est créé lors du traitement du bean Cbean. Bbean.timerMethod2 n'est pas visible dans la hiérarchie de classes de Cbean parce qu'il est neutralisé par la méthode Cbean.timerMethod2.
Considérons un autre exemple similaire au précédent, mais dans lequel l'annotation @Stateless serait supprimée des classes Abean et Bbean, de sorte que la classe Cbean serait la seule classe EJB. Dans ce cas, les seuls temporisateurs automatiques créés seraient ceux qui sont visibles par Cbean - un avec la méthode de rappel Abean.timerMethod1, et un avec la méthode de rappel Cbean.timerMethod2.
Bien que les beans puissent partager un code identique dans une méthode de rappel de beans héritée, le comportement d'exécution pourrait être polymorphique. Exemple :
public class Employee { @Schedule(hour=”1”, dayOfMonth=”-1”, info = "payroll timer") public void getSalaryIncrease() { printChecks(salary * rate()); } protected float rate() { return (float)1.01; } } public class Manager extends Employee { protected float rate() { return (float)1.15; } } public class Executive extends Manager { protected float rate() { return (float)1.30; } }
Dans l'exemple précédent, chaque instance de bean dispose d'un temporisateur automatique avec la méthode de rappel getSalaryIncrease(). Bien que le même code de rappel soit partagé par tous les temporisateurs, remarquez que le taux du calcul de l'augmentation de salaire utilisé par chaque bean est différent, à cause du polymorphisme. En effet, les méthodes de rappel de temporisateur peuvent être polymorphiques, comme le sont les autres méthodes Java.
Procédure
Résultats
Vous avez configuré à l'aide d'un programme ou automatiquement un temporisateur EJB qui est soit persistant, soit non persistant.