Eviter les doublons dans un pool de Thread avec les méthodes hashcode et equals

Dans mon article précédent, j’ai évoqué mon intervention rapide sur un projet utilisant un pool de Thread qui était mal géré. J’étais intervenu pour permettre de prioriser certaines tâches dans ce pool de Thread. Néanmoins, il y avait un autre souci, moins grave que le premier, (enfin pour le client) comme le volume assez conséquent de tâche. En Production, le pool de Thread était configuré à 5 tâches consécutives qui duraient plusieurs secondes chacune (allant même à une minute pour certaines). Toutes les 5 minutes, les tâches étaient injectées dans ce pool de Thread, par conséquent, on était régulièrement à 4000 tâches en attente en continu. Une grosse quantité de tâche arrivait toutes les 5 minutes pendant l’exécution des autres tâches déjà présentes dans la file d’attente, la file d’attente n’est jamais totalement dépilée. J’ai constaté rapidement en monitorant la production que de nombreuses tâches qui étaient en attente dans le pool de Thread étaient remises dans ce même pool au prochain cycle d’ajout, c’est à dire toutes les 5 minutes.

Pour diminuer ce volume, il y a 2 solutions possibles :

  • Ré-implémenter le système permettant de rajouter les tâches et ré-implémenter les tâches elles-mêmes qui sont beaucoup trop longues à s’exécuter. Bien sûr cette solution est trop coûteuse à réaliser car il faudrait tout réécrire et plusieurs développeurs étant déjà passés dessus, tout refaire est un aveu d’échec pour le client et c’est difficilement explicable à leur direction d’avoir perdu de l’argent sur plusieurs mois de développement.
  • La seconde solution, la plus rapide (donc le client est content), est de vérifier au moment de l’ajout de la tâche dans le pool de Thread si cette tâche est déjà présente.

C’est la seconde solution qu’on va réaliser en utilisant un décorateur, cela va nous permettre de rajouter des fonctionnalités supplémentaires à notre pool de Thread.

Lire la suite

Adaptateur de PriorityBlockingQueue avec FIFOEntry

Récemment, sur un petit projet, j’ai dû intervenir sur un pool de Thread géré par Spring Scheduling qui était saturé. Toutes les tâches asynchrones de l’application étaient gérées par ce pool de Thread. La file d’attente utilisée dans le pool de Thread est gérée par l’implémentation de l’api standard LinkedBlockingQueue qui implémente l’interface BlockingQueue. Cette file d’attente est une simple FIFO : le premier arrivé est le premier sorti. Néanmoins sur ce projet, la problématique était l’énorme quantité de tâches en attente ; par conséquent, les tâches étaient exécutées plusieurs heures après leur dépôt dans la file d’attente. Ceci n’est pas un problème en soi, mais dans ce projet un type de tâche particulière parmi tous les autres types de tâches devait être exécuté en priorité. La solution que j’ai trouvée est d’utiliser une file d’attente permettant d’établir un niveau de priorité en fonction de la tâche. Il suffira juste d’utiliser une autre implémentation de BlockingQueue permettant de gérer les priorités. Une implémentation existe déjà au sein de l’api standard Java PriorityBlockingQueue. Malheureusement, cette implémentation ne garantit pas l’ordre des tâches comportant une priorité équivalente mais une petite astuce dans la JavaDoc va nous conduire vers la bonne voie pour résoudre ce léger problème… Lire la suite

Creation d’un plugin JRebel

Dans un précédent article, je vous ai expliqué le fonctionnement de JRebel, la partie qui est un peu cachée par ZeroTurnaround.

Je vais vous expliquer comment faire simplement un plugin JRebel.

Sur mon précédent projet, l’internalisation de l’application utilisait l’implémentation de Spring org.springframework.context.support.ReloadableResourceBundleMessageSource

Cette implémentation propose un paramètre permettant de modifier le fichier de ressource à chaud.

Dans notre configuration Spring, nous avons déclaré ceci :

<bean id="messageSource"
 class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
 p:fallbackToSystemLocale="false" p:useCodeAsDefaultMessage="false"
 p:defaultEncoding="UTF-8">
 <description>Base message source to handle internationalization
 </description>
 <property name="basenames">
 <list>

 <!-- Libellés principaux -->
 <value>classpath:com/leconcurrentdebimedia/iris/common/labels/messages</value>
 </list>
 </property>
 </bean>

Il suffit juste d’ajouter dans la configuration Spring le cache à « 0 »

<bean id="messageSource"
 class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
 p:fallbackToSystemLocale="false" p:useCodeAsDefaultMessage="false"
 p:defaultEncoding="UTF-8" <strong>p:cacheSeconds="0"</strong>>
 <description>Base message source to handle internationalization
 </description>
 <property name="basenames">
 <list>

 <!-- Libellés principaux -->
 <value>classpath:com/leconcurrentdebimedia/iris/common/labels/messages</value>
 </list>
 </property>
 </bean>

Mais pour ce faire, il serait bien d’avoir une configuration Spring pour la production et une autre pour le développement.  On peut ajouter des profils Maven associés à une variable de production -1 et une variable de développement 0.

Bref il y a beaucoup de solutions possibles, on a choisi de le faire avec JRebel, vu qu’on l’utilise en développement. Comme cela, aucune configuration spécifique n’est nécessaire.

Lire la suite

Fonctionnement de JRebel

Récemment sur un projet, j’ai eu l’opportunité d’utiliser un nouvel outil : JRebel. Cela permet de modifier le code en cours d’exécution. ZeroTurnaround garantit que le développeur va gagner beaucoup de temps sur son développement car il sera dispensé de redémarrer à chaque modification.

L’outil est très simple à mettre en place, il est juste nécessaire d’ajouter au lancement de l’application l’agent JRebel. Un agent java est un jar disposant d’un MANIFEST particulier. L’agent JRebel fait environ 4 Mo. Ensuite tout fichier java qui est compilé (que ce soit avec votre IDE, javac ou Maven etc…) sera pris immédiatement à chaud au sein de la JVM. Aucune autre manipulation n’est nécessaire pour le développeur. Il est également possible de débugger facilement l’application en installant le plugin JRebel pour votre IDE (en ce qui me concerne j’utilise Eclipse).
Malheureusement, l’outil n’est pas gratuit, une licence est requise pour pouvoir l’utiliser ; il est néanmoins possible d’obtenir une licence gratuite de 30 jours.

Je l’ai utilisé tous les jours pendant 8 mois (l’entreprise disposait d’une licence) sur un projet qui est une application web tournant sous Tomcat avec du JSF et Spring, bref une application classique dans beaucoup de boîtes. En effet l’outil m’a permis de tester mes modifications rapidement sans perdre un temps considérable, j’avais l’impression de refaire du php : on code, on appuie sur la touche F5 du navigateur web et boum on voit la modification. C’est quand même très pratique et cela facilite grandement le développement. De plus, il ne permet pas uniquement de modifier le code à chaud, il gère également les différents framework du marché, en allant des framework de présentation, jsf, struts2, gwt, tiles… en passant par les framework de persistance, hibernate, spring, guice etc etc…

Par exemple :

  • Avec JSF, JRebel paramètre automatiquement  le cache de « facelets.REFRESH_PERIOD » à 0. Cela permet de prendre immédiatement à chaud les fichiers xhtml.
  • Avec Spring, JRebel détecte automatiquement une modification dans le contexte Spring. Un ajout d’une annotation « Autowired » par exemple, sur une des classes et JRebel recharge automatiquement le contexte Spring.

Bref, cela serait trop long de vous décrire l’ensemble des nouvelles fonctionnalités qu’apporte JRebel sur les différents framework du marché. Sur le site de JRebel, il y a un récapitulatif de chaque framework supporté, et la liste est très conséquente, avec les fonctionnalités que cela apporte : http://zeroturnaround.com/software/jrebel/features/frameworks/

Si les framework que vous utilisez font partie de la liste, l’outil devient encore plus intéressant pour le développeur.

J’ai commencé à me poser plusieurs questions car je suis de nature curieuse :

  • Comment fonctionne-t-il pour prendre en compte le code compilé ?
  • Pourquoi mon application est-elle légèrement plus lente avec JRebel que sans ?

J’ai donc cherché mes informations sur le site de JRebel et je suis tombé sur cet article : http://zeroturnaround.com/jrebel/reloading_java_classes_401_hotswap_jrebel et en particulier sur le chapitre « How does this work? ». Ce chapitre explique en gros le fonctionnement du remplacement du bytecode, j’ai voulu en savoir plus et c’est pour cela que  j’ai décidé de fouiller un peu dans le code de JRebel pour comprendre son fonctionnement…

Lire la suite

Utiliser Slf4j dans un plugin Maven

Lors de la réalisation d’un plugin Maven utilisant une librairie externe, j’ai été confronté à un petit problème :(. Comment tracer les logs d’une librairie dans le logger de Maven? A l’exécution d’un plugin, Maven trace avec son logger interne. Le logger de Maven possède 4 niveaux : debug, info, warn et error. Le niveau « debug » est activé avec le paramètre « -X » ou « –debug », par exemple « mvn clean install -X ». Ce logger est fourni au sein de Mojo API de maven et plus précisément la classe abstraite AbstractMojo qui hérite le Mojo du plugin. Imaginons un plugin qui tire une dépendance et que celle-ci trace avec slf4j, on sait par avance qu’a l’exécution du plugin, toutes les traces issues de slf4j ne seront pas tracés au sein de Maven. La réponse est très simple, réaliser un binding slf4j vers le logger de Maven. Ainsi toutes les traces issues de slf4j seront redirigées vers le logger de Maven. 2 étapes importantes doivent être réalisées :

  • Implémenter le binding slf4j pour Maven
  • Injecter le logger maven dans le binding à l’instancialisation du plugin maven.

Lire la suite