Ejecutar la Aplicación de Test TestWrapper

Esta página describirá la aplicación de ejemplo TestWrapper, que viene incluida con el Wrapper para demostrar varias de sus funciones de recuperación de errores.

Ejecutando en una Consola

Para ejecutar la aplicación en una consola, ejecute el siguiente script en el directorio bin:

Windows:
TestWrapper.bat
Unix:
./testwrapper console

NOTA

Antes de la versión 3.0.5, el script testwrapper en UNIX intentaba escribir un archivo PID al directorio /var/run. Usuarios no raíz (non-root) tendrían que cambiar la variable PIDDIR del script a un directorio teniendo los permisos apropiados. Esto ya no es un problema desde la versión 3,0,5, ya que el Wrapper ahora escribe el archivo PID en la misma ubicación que el script.

Cuando la aplicación inicie, la siguiente ventana abrirá:

Usted también verá la siguiente salida en la consola:

Salida de Datos de la Consola:
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()

Empezaremos por la salida de la consola. La primera columna de datos muestra la origen de la salida de datos. Las líneas que empiezan con "wrapper" vienen de la aplicación nativa del Wrapper. Las líneas que empiezan con "jvm 1" vienen de la salida de la JVM. El número después de "jvm" indica el número de JVM(s) lanzada(s) desde que el Wrapper ha sido iniciado. Veremos como funciona cuando empezarmos a usar la interfaz de TestWrapper.

Por defecto, la salida de datos de la consola también es registrada en logs/wrapper.log. Sin embargo, el formato del archivo de registro se configura para que también incluya el nivel de registro y el marca de tiempo de cada mensage registrado.

Salida de Datos en el Archivo de Registro:
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()

Es posible reconfigurar separadamente el formato, así como el nivel de registro de cada salida de datos. Esto se puede hacer usando las siguientes propiedades:

La aplicación de ejemplo TestWrapper le presenta una intefaz mostrando varios botones para probar las varias funcionalidades del Wrapper. Cada botón se describe a seguir con la salida de datos que verá en la consola si el botón es activado.

Como una alternativa a la interfaz gráfica del usuario (GUI), la aplicación TestWrapper puede ser controlada exclusivamente desde un terminal. Este modo, llamado 'console' (consola), tiene las mismas funcionalidades que la GUI, pero la aplicación esperará por entradas del usuario, y los testes pueden ser activados al esribir comandos en el terminal, en vez de clicar en los botones.

TestWrapper Application siendo ejecutada en modo '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.

para lanzar la aplicación en modo 'console', es necesario añadir un argumento 'console' adicional. En UNIX, este argumento no debe ser confundido con el comando 'console' pasado al script (la palabra 'console' debe repetirse 2 veces al lanzar el script).

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

Se puede cerrar la aplicación a cualquier momento cerrando la ventana o usando los botones "Stop()" y "Exit()". También puede presionar CTRL-C en el terminal para solicitar un cierre limpio.

Probando las Características del Wrapper (Salidas Internas y Problemas)

Esta sección demostrará como el Wrapper responde a varios eventos. Cada uno de ellos pueden ser probados al presionar los botones en la interfaz de usuario.

Stop

La JVM sale limpiamente al llamar WrapperManager.stop(0).

Salida de Datos de la Consola:
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

Como lo puede ver, la aplicación tuvo su método stop() llamado, y se detuvo limpiamente.

Exit

El botón de Exit pone a prueba la habilidad del Wrapper de detectar una llamada inesperada a System.exit() y detener la aplicación elegantemente.

Salida de Datos de la Consola:
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

Como un ejercicio, edite su archivo conf/wrapper.conf y descomente la propiedad wrapper.disable_shutdown_hook=TRUE. (Asegúrese de comentar nuevamente cuando haya terminado)

Ahora vuelva a ejecutar la aplicación TestWrapper.

Salida de Datos de la Consola:
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()

Notará que el Wrapper ya no detecta la llamada a System.exit() y piensa que la JVM esta bloqueda (crash), y entonces la reinicia.

Halt

Este botón Halt llama a un método de bajo nivel para detener la JVM forzadamente. En este caso, En este caso, los shutdown hooks no son ejecutados y el Wrapper no tiene manera alguna de detectarlos.

Salida de Datos de la Consola:
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()

Note que el Wrapper piensa que la JVM esta bloqueada y la reinicia.

Solicitar Reinicio

Reinicia la máquina JVM limpiamente al llamar a WrapperManager.restart()

Salida de Datos de la Consola:
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()

Como lo puede ver, la aplicación tuvo su método stop() llamado y ha reiniciado limpiamente.

Violación de Acceso Nativo

El Java Service Wrapper incluye una librería nativa denominada "lightweight", la cual es usada para manejar eventos del sistema. La librería también contiene un método nativo, que se usa para pruebas que causan violaciones de acceso nativo debido a una referencia "NULL".

Dependiendo de la JVM, la salida de datos también será diferente.

Salida de Datos de la Consola (Oracle JVM):
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...

Como puede ver, una violación de acceso hizo con que la JVM mostrara un error y terminara. El Wrapper inmediatamente detecta eso y después de una pausa de 5 segundos, reinicia la aplicación en una nueva JVM, como se ve en jvm 2. Toda la información disponible sobre el bloqueo (crash) ha sido registrada para referencia futura.

Simular bloqueo de JVM

Esta prueba hace que el Wrapper piense que la JVM se ha bloqueado. Después de 30 segundos, el tiempo del Wrapper se acaba y éste decide que la JVM no regresará a su estado normal y la reinicia.

Salida de Datos de la Consola:
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()

Probando las Características del Wrapper (Salidas Externas)

La sección anterior cubrió todas las formas en las que una aplicación puede salir o terminar repentinamente por su cuenta. Existen otros factores externos de los cuales el también Wrapper puede protegerse.

CTRL-C

La mayoría de las aplicaciones Java son eliminadas si el usuario presiona CTRL-C, finaliza sesión en Windows, etc. Algunos de estos problemas se pueden solucionar con un Shutdown Hook. Pero el Wrapper implementa esto al usar una librería nativa para que directamente capture las señales del sistema. Esto hace posible tener una aplicación Java instalada como un servicio de Windows sin que se detenga cuando un usuario cierra sesión.

Solo como prueba, trate de presionar CTRL-C en la consola (ventana de comandos).

Salida de Datos de la Consola:
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

También puede ver algunas variaciones sobre esto al cerrar sesión cuando la aplicación de la consola aún esté funcionando. El Wrapper terminará la aplicación correctamente.

Salida de Datos de la Consola:
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

En las plataformas Unix, solo se puede presionar CTRL-C si el comando 'console' fue pasado al script usado para iniciar el Wrapper.

Si el Wrapper fue lanzado usando el comando 'start', este será separado en un proceso diferente como un Servicio/Demonio, y usted no podrá acceder a la consola. Para detener instancias separadas del Wrapper, ejecute el mismo script usado para iniciar el Wrapper, pero de esta vez, especifque el comando 'stop':

Salida de Datos de la Consola:
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

Terminación del Proceso

También es posible aunque no usual, que el proceso de la aplicación pudiera ser eleminado por otra aplicación. Esta prueba también simula casos en que la JVM muere repentinamente por su cuenta. En sistemas Unix, se puede eliminar el proceso Java con una señal kill -9. En sistemas Windows, abra el Administrador de Tareas y seleccione la pestaña de Procesos. Después, busque el proceso java.exe a ser eliminado y elimínelo.

Salida de Datos de la Consola:
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()

El Wrapper será reiniciado sin ningún problema.

Si en lugar de eliminar el proceso Java, el proceso del Wrapper es eliminado, entonces el WrapperManager se pondrá en modo de recuperación. El WrapperManager que se encuentra dentro del proceso Java reacciona a la pérdida del Wrapper asumiendo que el proceso Java está abandonado. Esto hace con que la JVM sea apagada limpiamente 30 segundos después de que el proceso del Wrapper es eliminado.

Sistema Bajo Alta Carga o Suspensión de Sistema

Hay casos en los que al Wrapper, la JVM o a ambos se les negará ciclos de CPU durante un período de tiempo prolongado. Esto puede suceder si un proceso hostil de recursos empieza a tomar 100% de la CPU durante un período de tiempo. Esto también es posible si el usuario suspende el acceso del sistema a RAM o disco. Cuando se resume el sistema, todas las aplicaciones en ejecución habrán experimentado alguna perdida de tiempo. El Wrapper es capaz de detectar que esto ha sucedido, por lo que es posible evitar hacer reinicios del proceso de la JVM que no sean necesarios. El siguiente resultado muestra lo que sucede cuando el sistema es suspendido a RAM por 255 segundos antes de ser resumido.

Salida de Datos de la Consola:
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.

En la versión Wrapper 3.1.0, un nuevo mecanismo de temporizador fue añadido, permitiendo al Wrapper a manejar casos en que está ejecutando en un estado de falta de CPU de manera confiable porque el conteo de ticks se incrementa a una tasa que refleja la cantidad de CPU que se recibe, en lugar de ser absoluta. Esto significa que tiempos de espera agotados debido a altas cargas son muy poco probables. Asegúrese que la propiedad wrapper.use_system_time está configurada en FALSE para que el mecanismo de temporizador sea habilitado.

Ejecutando como un Servicio de Windows

Cuando se ejecuta como un servicio de Windows, la aplicación TestWrapper no podrá mostrar su interfaz de usuario. Esto le impide iniciar las pruebas descritas anteriormente. Sin embargo, podemos hacer varias pruebas para verificar que el Wrapper esta siendo usado como Servicio de Windows correctamente.

Lo primero que se tiene que hacer es instalar la aplicación TestWrapper como un Servicio de Windows al ejecutar el siguiente comando:

Comando:
InstallTestWrapper-NT.bat
Salida de Datos:
wrapper  | TestWrapper Application installed.

Una vez que la aplicación TestWrapper es instalada como Servicio, lo que queremos hacer es iniciarla.

Comando:
net start TestWrapper
Salida de Datos:
The TestWrapper Application service is starting.
The TestWrapper Application service was started successfully.

El servicio se puede desinstalar ejecutando el siguiente comando:

UninstallTestWrapper-NT.bat
Si el servicio está siendo ejecutado, verá la siguiente salida de datos:
wrapper  | Service is running.  Stopping it...
wrapper  | Waiting to stop...
wrapper  | TestWrapper Application stopped.
wrapper  | TestWrapper Application removed.

Si revisa el contenido de logs/wrapper.log, verá que la salida de datos es muy similar a la de la consola. La diferencia es que en esta ocasión el mensaje de inicio informa que la aplicación está siendo iniciada como un servicio, en vez de como consola.

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

A continuación vea los resultados de varias acciones que pueden sucitarse en un Servicio de Windows:

Cierre y Reinicio de Sesión de Usuario

Una entrada de registro se realiza cuando el usuario termina sesión, pero el servicio no se ve afectado.

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)

Reiniciando la máquina

Esto dará como resultado una señal para cerrar sesión "logout" seguido de una señal de apagado "shutdown". El servicio será apagado elegantemente para después regresar una vez que la máquina reinicie.

Una entrada de registro se realiza cuando el usuario cierra sesión, pero el servicio no se ve afectado.

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

Por favor lea esta página para información detallada de cómo controlar el Wrapper como un Servicio de Windows.

Ejecutando como un Demonio en Unix

El Wrapper puede ser iniciado usando el comando 'start' para que se ejecute en segundo plano. Si se inicia desde un terminal que no puede exibir la GUI, la aplicación cambiará a modo consola, pero no será muy útil, ya que el Demonio no puede ser controlado con la consola.

Unix:
./testwrapper start

Una vez que la aplicación se inicia, la interfaz de usuario de la aplicación TestWrapper que se ejecuta como un demonio puede ser usada exactamente como cuando se ejecuta como una aplicación de consola.

Para detener las instancias del Wrapper siendo ejecutado como un demonio, use el mismo script con el comando 'stop'.

Unix:
./testwrapper stop

Por favor lea esta página para una descripción completa de los comandos que pueden usarse para controlar el Wrapper mientra es ejecutado como Demonio Unix.