Exécution de l'application d'exemple TestWrapper

Cette page décrit l'application d'exemple TestWrapper, fournie avec le Wrapper pour démontrer plusieurs de ses fonctionnalités de récupération après défaillance.

Exécution dans une console

Pour exécuter l'application dans une console, lancez le script suivant situé dans le répertoire bin :

Windows :
TestWrapper.bat
Unix :
./testwrapper console

NOTE

Avant la version 3.0.5, le script testwrapper sous UNIX tentait d'écrire un fichier PID dans le répertoire /var/run. Les utilisateurs non root devaient modifier la variable PIDDIR du script pour la faire pointer vers un répertoire disposant des permissions appropriées. Ce n'est plus un problème depuis la version 3.0.5, car le Wrapper écrit le fichier PID au même emplacement que le script.

Lorsque l'application démarre, la fenêtre suivante s'affiche :

Vous devriez également voir la sortie suivante dans la console :

Sortie console :
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()

Commençons par la sortie console. La première colonne de données affiche la source de la sortie. Les lignes commençant par « wrapper » proviennent de l'application native Wrapper. Les lignes commençant par « jvm 1 » proviennent de la sortie de la JVM. Le numéro après « jvm » indique le nombre de JVM lancée(s) depuis le démarrage du Wrapper. Nous verrons comment cela fonctionne lorsque nous commencerons à utiliser l'interface de TestWrapper.

Par défaut, toute la sortie console est également enregistrée dans logs/wrapper.log. Cependant, le format du fichier journal est configuré pour inclure également le niveau de log et les horodatages de chaque message consigné.

Sortie dans le fichier journal :
STATUS | wrapper  | 2001/12/06 16:18:27 | --> Wrapper Started as Console
STATUS | wrapper  | 2001/12/06 16:18:28 | Launching a JVM...
INFO   | jvm 1    | 2001/12/06 16:18:29 | Initializing...
INFO   | jvm 1    | 2001/12/06 16:18:30 | Wrapper (Version 3.x.x)
INFO   | jvm 1    | 2001/12/06 16:18:30 | 
INFO   | jvm 1    | 2001/12/06 16:18:30 | start()

Il est possible de reconfigurer séparément le format ainsi que le niveau de log de chaque sortie. Cela peut être fait à l'aide des propriétés suivantes :

Par défaut, l'application TestWrapper vous présente une interface affichant plusieurs boutons pour tester diverses fonctionnalités du Wrapper. Chaque bouton est décrit ci-dessous avec la sortie que vous verrez dans la console si le bouton est activé.

En alternative à l'interface graphique, l'application TestWrapper peut être contrôlée exclusivement depuis un terminal. Ce mode, appelé « console », offre les mêmes fonctionnalités que l'interface graphique, mais l'application attendra les saisies de l'utilisateur, et les tests peuvent être déclenchés en écrivant des commandes dans le terminal plutôt qu'en cliquant sur des boutons.

Application TestWrapper exécutée en mode « console » :
jvm 1    | WrapperManager: Initializing...
jvm 1    | TestWrapper: Initializing...
jvm 1    | TestWrapper: start()
jvm 1    | TestWrapper: ActionServer Enabled.
jvm 1    | TestWrapper:   Telnet localhost 9999
jvm 1    | TestWrapper:   Commands:
jvm 1    | TestWrapper:     S: Shutdown
jvm 1    | TestWrapper:     H: Expected Halt
jvm 1    | TestWrapper:     R: Restart
jvm 1    | TestWrapper:     D: Thread Dump
jvm 1    | TestWrapper:     U: Unexpected Halt (Simulate crash)
jvm 1    | TestWrapper:     V: Access Violation (Actual crash)
jvm 1    | TestWrapper:     G: Make the JVM appear to be hung.
jvm 1    | TestWrapper:
jvm 1    |
jvm 1    | Start prompting for actions.
jvm 1    | Input an action ('help' for a list of actions):
help
jvm 1    | Read action: help
jvm 1    |
jvm 1    | [ACTIONS]
jvm 1    |    help                     : Shows this help message
jvm 1    |   Actions which should cause the Wrapper to exit cleanly:
jvm 1    |    stop0                    : Calls WrapperManager.stop(0)
jvm 1    |    exit0                    : Calls System.exit(0)
jvm 1    |    stopimmediate0           : Calls WrapperManager.stopImmediate(0)
jvm 1    |    stopandreturn0           : Calls WrapperManager.stopAndReturn(0)
jvm 1    |   Actions which should cause the Wrapper to exit in an error state:
jvm 1    |    stop1                    : Calls WrapperManager.stop(1)
jvm 1    |    exit1                    : Calls System.exit(1)
jvm 1    |    nestedexit1              : Calls System.exit(1) within WrapperListener.stop(1) callback
jvm 1    |    stopimmediate1           : Calls WrapperManager.stopImmediate(1)
jvm 1    |   Actions which should cause the Wrapper to restart the JVM:
jvm 1    |    access_violation_native  : Calls WrapperManager.accessViolationNative()
jvm 1    |    appear_hung              : Calls WrapperManager.appearHung()
jvm 1    |    halt0                    : Calls Runtime.getRuntime().halt(0)
jvm 1    |    halt1                    : Calls Runtime.getRuntime().halt(1)
jvm 1    |    restart                  : Calls WrapperManager.restart()
jvm 1    |    restartandreturn         : Calls WrapperManager.restartAndReturn()
jvm 1    |   Additional Tests:
jvm 1    |    appear_slow_1            : Calls WrapperManager.appearSlow(1)
jvm 1    |    appear_slow_5            : Calls WrapperManager.appearSlow(5)
jvm 1    |    appear_slow_reset        : Calls WrapperManager.appearSlow(0) to return to normal
jvm 1    |    deadlock                 : Executes some deadlocking code to test deadlock detection
jvm 1    |    outofmemory              : Simulates an OutOfMemoryError being thrown
jvm 1    |    ignore_events            : Makes this application ignore control events.
jvm 1    |    dump                     : Calls WrapperManager.requestThreadDump()
jvm 1    |    deadlock_out             : Deadlocks the JVM's System.out and err streams.
jvm 1    |    users                    : Start polling the current and interactive users.
jvm 1    |    groups                   : Start polling the current and interactive users with groups.
jvm 1    |    console                  : Prompt for actions in the console.
jvm 1    |    idle                     : Do nothing just run in idle mode.
jvm 1    |    properties               : Dump all System Properties to the console.
jvm 1    |    configuration            : Dump all Wrapper Configuration Properties to the console.
jvm 1    |    gc                       : Perform a GC sweep.
jvm 1    |    is_professional          : Displays whether or not this is a Professional Edition Wrapper.
jvm 1    |    is_standard              : Displays whether or not this is at least a Standard Edition Wrapper.
jvm 1    |    exec <cmd>               : Executes a managed child process.
jvm 1    |    exec_detached <cmd>      : Executes a detached child process.

Pour lancer l'application en mode « console », vous devez lui passer un argument « console » supplémentaire. Sous UNIX, cet argument ne doit pas être confondu avec la commande « console » passée au script (le mot « console » doit donc être répété deux fois lors du lancement du script).

Windows :
TestWrapper.bat console
Unix :
./testwrapper console console

Vous pouvez arrêter l'application à tout moment en fermant la fenêtre ou en utilisant les boutons « Stop() » et « Exit() ». Vous pouvez également appuyer sur CTRL-C dans le terminal pour demander un arrêt propre.

Test des fonctionnalités du Wrapper (sorties et problèmes internes)

Cette section montrera comment le Wrapper réagit à divers événements. Chacun de ces événements peut être testé en appuyant sur les boutons de l'interface utilisateur.

Arrêt

Termine la JVM proprement en appelant WrapperManager.stop(0).

Sortie console :
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
jvm 1    | stop(0)
wrapper  | <-- Wrapper Stopped

Comme vous pouvez le voir, la méthode stop() de l'application a été appelée et celle-ci a été arrêtée proprement.

Sortie

Ce bouton Exit teste la capacité du Wrapper à intercepter un appel inattendu à System.exit() et à arrêter l'application de façon élégante.

Sortie console :
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
jvm 1    | stop(0)
jvm 1    | here
wrapper  | <-- Wrapper Stopped

À titre d'exercice, modifiez votre fichier conf/wrapper.conf et décommentez la propriété wrapper.disable_shutdown_hook=TRUE. (Veillez à la recommenter une fois terminé.)

Relancez maintenant l'application TestWrapper.

Sortie console :
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
wrapper  | JVM exited unexpectedly.
wrapper  | Launching a JVM...
jvm 2    | Initializing...
jvm 2    | Wrapper (Version 3.x.x)
jvm 2    |
jvm 2    | start()

Vous remarquerez que le Wrapper n'intercepte plus l'appel à System.exit(), il pense donc que la JVM a planté et la redémarre.

Arrêt forcé

Ce bouton Halt appelle une méthode de très bas niveau pour arrêter la JVM de force. Dans ce cas, les hooks d'arrêt ne sont pas exécutés et le Wrapper n'a aucun moyen de les intercepter.

Sortie console :
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
wrapper  | JVM exited unexpectedly.
wrapper  | Launching a JVM...
jvm 2    | Initializing...
jvm 2    | Wrapper (Version 3.x.x)
jvm 2    |
jvm 2    | start()

Remarquez que le Wrapper pense que la JVM a planté et la redémarre.

Demande de redémarrage

Redémarre la JVM proprement en appelant WrapperManager.restart()

Sortie console :
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
wrapper  | JVM requested a restart.
jvm 1    | stop(0)
wrapper  | Launching a JVM...
jvm 2    | Initializing...
jvm 2    | Wrapper (Version 3.x.x)
jvm 2    |
jvm 2    | start()

Comme vous pouvez le voir, la méthode stop() de l'application a été appelée et celle-ci a été redémarrée proprement.

Violation d'accès native

Le Java Service Wrapper inclut une bibliothèque native légère utilisée pour gérer les événements système. La bibliothèque contient également une méthode native, utilisée pour les tests, qui provoque une violation d'accès dans le code natif en raison d'une référence « NULL ».

Selon la JVM, cela produira une sortie différente.

Sortie console (JVM Oracle) :
wrapper  | -->jvm 1    | WrapperManager: WARNING: Attempting to cause an access violation...
jvm 1    | #
jvm 1    | # A fatal error has been detected by the Java Runtime Environment:
jvm 1    | #
jvm 1    | #  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007fffc9aee46f, pid=14352, tid=12948
jvm 1    | #
jvm 1    | # JRE version: Java(TM) SE Runtime Environment (8.0_45-b15) (build 1.8.0_45-b15)
jvm 1    | # Java VM: Java HotSpot(TM) 64-Bit Server VM (25.45-b02 mixed mode windows-amd64 compressed oops)
jvm 1    | # Problematic frame:
jvm 1    | # C  [wrapper.dll+0xe46f]  Java_org_tanukisoftware_wrapper_WrapperManager_accessViolationInner+0x1f
jvm 1    | #
jvm 1    | # Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
jvm 1    | #
jvm 1    | # An error report file with more information is saved as:
jvm 1    | # C:\wrapper\bin\hs_err_pid14352.log
jvm 1    | #
jvm 1    | # If you would like to submit a bug report, please visit:
jvm 1    | #   http://bugreport.java.com/bugreport/crash.jsp
jvm 1    | # The crash happened outside the Java Virtual Machine in native code.
jvm 1    | # See problematic frame for where to report the bug.
jvm 1    | #
wrapper  | JVM exited unexpectedly.
wrapper  | Launching a JVM...
jvm 2    | WrapperManager: Initializing...
jvm 2    | TestWrapper: Initializing...

Comme vous pouvez le voir, une violation d'accès a amené la JVM à afficher un dump d'erreur puis à se terminer. Le Wrapper détecte immédiatement cela et, après une pause de 5 secondes, redémarre l'application dans une nouvelle JVM, comme on peut le voir avec jvm 2. Toutes les informations disponibles sur le plantage ont été consignées pour référence future.

Simuler un blocage de la JVM

Ce test fait croire au Wrapper que la JVM s'est bloquée. Après 30 secondes, le Wrapper expire et décide que la JVM ne reviendra pas, puis la redémarre.

Sortie console :
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
jvm 1    | WARNING: Making JVM appear to be hung...
wrapper  | JVM appears hung: Timed out waiting for signal from JVM.
wrapper  | JVM did not exit on request, terminated
wrapper  | Launching a JVM...
jvm 2    | Initializing...
jvm 2    | Wrapper (Version 3.x.x)
jvm 2    |
jvm 2    | start()

Test des fonctionnalités du Wrapper (sorties externes)

La section ci-dessus a couvert toutes les façons dont une application peut se terminer ou mourir de son propre chef. Il existe d'autres facteurs externes contre lesquels le Wrapper peut également se protéger.

CTRL-C

La plupart des applications Java se terminent de façon assez abrupte si l'utilisateur appuie sur CTRL-C, se déconnecte de Windows, etc. Vous pouvez contourner certains de ces problèmes avec un Shutdown Hook. Le Wrapper implémente cela en utilisant une bibliothèque native pour capturer directement les signaux système. Cela permet d'installer une application Java en tant que service Windows sans qu'elle soit arrêtée lorsqu'un utilisateur se déconnecte.

À titre de test, essayez d'appuyer sur CTRL-C dans la console (fenêtre de commande).

Sortie console :
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
wrapper  | CTRL-C trapped.  Shutting down.
jvm 1    | stop(0)
wrapper  | <-- Wrapper Stopped

Vous pouvez également observer des variantes en vous déconnectant alors que l'application console est encore en cours d'exécution. Le Wrapper terminera correctement l'application.

Sortie console :
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    | 
jvm 1    | start()
wrapper  | User logged out.  Shutting down.
jvm 1    | stop(0)
wrapper  | <-- Wrapper Stopped

Sur les plateformes Unix, vous ne pouvez appuyer sur CTRL-C que si le script utilisé pour lancer le Wrapper a reçu la commande « console ».

Si le Wrapper a été lancé à l'aide de la commande « start », il a alors été démarré dans un processus différent en tant que service/démon, vous n'avez donc pas accès à la console. Pour arrêter les instances lancées du Wrapper, exécutez le même script utilisé pour lancer le Wrapper, en spécifiant cette fois la commande « stop » :

Sortie console :
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
wrapper  | Shutting down.
jvm 1    | stop(0)
wrapper  | <-- Wrapper Stopped

Terminaison du processus

Il est également possible, bien que peu probable, que le processus de l'application soit tué par une autre application. Ce test simule également les cas où la JVM meurt très soudainement de son propre chef. Sur les systèmes UNIX, vous pouvez tuer le processus Java avec un signal kill -9. Sur les systèmes Windows, ouvrez le Gestionnaire des tâches, puis sélectionnez l'onglet Processus. Ensuite, trouvez le processus java.exe à tuer, puis tuez-le.

Sortie console :
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
wrapper  | JVM exited unexpectedly.
wrapper  | Launching a JVM...
jvm 2    | Initializing...
jvm 2    | Wrapper (Version 3.x.x)
jvm 2    |
jvm 2    | start()

Le Wrapper redémarrera la JVM sans aucun problème.

Si, plutôt que de tuer le processus Java, c'est le processus Wrapper qui est tué, alors WrapperManager sera en mode récupération. Le WrapperManager à l'intérieur du processus Java réagit à la perte du Wrapper en considérant que le processus Java est abandonné. Cela conduit à l'arrêt propre de la JVM 30 secondes après la mort du processus Wrapper.

Système sous forte charge ou mise en veille du système

Il existe des cas où le Wrapper, la JVM ou les deux se voient refuser des cycles CPU pendant une période prolongée. Cela peut se produire si un processus gourmand en ressources commence à utiliser 100 % du CPU pendant un certain temps. C'est également possible si l'utilisateur met le système en veille sur RAM ou sur disque. Lorsque le système reprend, toutes les applications en cours d'exécution auront subi un manque de temps. Le Wrapper est capable de reconnaître que cela s'est produit, ce qui permet d'éviter des redémarrages inutiles du processus JVM. La sortie suivante montre ce qui se passe lorsque le système est mis en veille sur RAM pendant 255 secondes avant d'être repris.

Sortie console :
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
jvm 1    | JVM Process has not received any CPU time for 255 seconds.  Extending timeouts.
wrapper  | Wrapper Process has not received any CPU time for 255 seconds.  Extending timeouts.

À partir de la version 3.1.0 du Wrapper, un nouveau mécanisme de minuterie a été ajouté, qui permet au Wrapper de gérer de manière fiable les cas où il s'exécute dans un état de famine CPU, car le compteur de ticks est incrémenté à un rythme qui reflète la quantité de CPU reçue, plutôt que d'être absolu. Cela signifie que les expirations dues à des charges élevées sont très peu probables. Assurez-vous simplement que la propriété wrapper.use_system_time est définie sur FALSE pour que le mécanisme de minuterie soit activé.

Exécution en tant que service Windows

Lorsqu'elle s'exécute en tant que service Windows, l'application TestWrapper ne pourra pas afficher son interface utilisateur. Cela vous empêche de lancer les tests décrits ci-dessus. Nous pouvons toutefois effectuer quelques tests pour vérifier que le Wrapper se comporte correctement en tant que service Windows.

La première chose à faire est d'installer l'application TestWrapper en tant que service Windows en exécutant la commande suivante :

Commande :
InstallTestWrapper-NT.bat
Vous verrez la sortie :
wrapper  | TestWrapper Application installed.

Une fois l'application TestWrapper installée en tant que service, nous voudrons la démarrer.

Commande :
net start TestWrapper
Vous verrez la sortie :
The TestWrapper Application service is starting.
The TestWrapper Application service was started successfully.

Le service peut être désinstallé en exécutant la commande suivante :

UninstallTestWrapper-NT.bat
Si le service est en cours d'exécution, vous verrez la sortie :
wrapper  | Service is running.  Stopping it...
wrapper  | Waiting to stop...
wrapper  | TestWrapper Application stopped.
wrapper  | TestWrapper Application removed.

Si vous consultez le contenu de logs/wrapper.log, vous verrez une sortie très similaire à celle de la console (sauf que, cette fois, le message de démarrage vous informe que l'application est démarrée en tant que service plutôt qu'en tant que console).

wrapper.log
wrapper  | 2001/12/06 17:34:21 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:34:21 | Launching a JVM...
jvm 1    | 2001/12/06 17:34:22 | Initializing...
jvm 1    | 2001/12/06 17:34:22 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:34:22 |
jvm 1    | 2001/12/06 17:34:22 | start()

Voici les résultats de plusieurs autres actions pouvant se produire sur un service Windows :

Déconnexion puis reconnexion de l'utilisateur

Une entrée de journal est créée lorsque l'utilisateur se déconnecte, mais le service n'est pas affecté.

wrapper.log
wrapper  | 2001/12/06 17:39:39 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:39:40 | Launching a JVM...
jvm 1    | 2001/12/06 17:39:40 | Initializing...
jvm 1    | 2001/12/06 17:39:40 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:39:40 |
jvm 1    | 2001/12/06 17:39:41 | start()
wrapper  | 2001/12/06 17:40:07 | User logged out.  Ignored.
jvm 1    | 2001/12/06 17:40:07 | controlEvent(202)

Redémarrage de la machine

Cela entraînera un signal de « déconnexion » suivi d'un signal d'« arrêt ». Le service sera arrêté proprement, puis reviendra après le redémarrage de la machine.

Une entrée de journal est créée lorsque l'utilisateur se déconnecte, mais le service n'est pas affecté.

wrapper.log
wrapper  | 2001/12/06 17:41:04 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:41:05 | Launching a JVM...
jvm 1    | 2001/12/06 17:41:05 | Initializing...
jvm 1    | 2001/12/06 17:41:05 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:41:05 |
jvm 1    | 2001/12/06 17:41:05 | start()
wrapper  | 2001/12/06 17:41:25 | User logged out.  Ignored.
jvm 1    | 2001/12/06 17:41:26 | controlEvent(202)
wrapper  | 2001/12/06 17:41:27 | Machine is shutting down.
jvm 1    | 2001/12/06 17:41:27 | controlEvent(203)
jvm 1    | 2001/12/06 17:41:28 | stop(0)
wrapper  | 2001/12/06 17:41:29 | <-- Wrapper Stopped
wrapper  | 2001/12/06 17:44:12 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:44:12 | Launching a JVM...
jvm 1    | 2001/12/06 17:44:17 | Initializing...
jvm 1    | 2001/12/06 17:44:21 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:44:21 |
jvm 1    | 2001/12/06 17:44:23 | start()

Veuillez lire cette page pour des informations détaillées sur la façon de contrôler le Wrapper en tant que service Windows.

Exécution en tant que démon Unix

Le Wrapper peut être lancé à l'aide de la commande « start » pour s'exécuter en arrière-plan. S'il est lancé depuis un terminal incapable d'afficher l'interface graphique, l'application basculera en mode console, mais cela ne sera pas très utile car le démon ne peut pas être contrôlé via la console.

Unix :
./testwrapper start

Une fois l'application démarrée, l'interface de l'application TestWrapper exécutée en tant que démon peut être utilisée exactement comme lors de l'exécution en tant qu'application console.

Pour arrêter les instances du Wrapper s'exécutant en tant que démon, utilisez le même script avec la commande « stop ».

Unix :
./testwrapper stop

Veuillez lire cette page pour une description complète des commandes pouvant être utilisées pour contrôler le Wrapper exécuté en tant que démon Unix.