Java como lenguaje fue diseñado para que fuera imposible que el código de usuario desarrollado diera como resultado una aplicación bloqueada (crash). Cualquier error podría resultar en una excepción limpia que sería generada para poder ser detectada y manejada adecuadamente. En realidad tanto desarrolladores de Java como un administrador de sistemas, saben que la máquina virtual Java (JVM) puede bloquearse en algún momento de su ciclo de vida. Esto se debe a que la JVM es un programa escrito con un código nativo y como cualquier otro programa también experimenta errores.

Como cualquier programa cuando Java se bloquea literalmente muere, llevándose consigo su aplicación. Esto puede ser desastroso si la aplicación es un sistema de misión crítica. La aplicación estará fuera de servicio y dicha inactividad puede que no sea detectada hasta que algún cliente visite por ejemplo el sitio web o después de algunas horas hasta que el departamento de logística se percate que las órdenes no estan siendo recibidas. Una vez que se haya detectado que la aplicación esta inactiva, tomará una hora o más tiempo hasta que el administrador pueda llegar para reiniciarla.

Solución

La Solución a este problema es tener una aplicación que pueda monitorear cuidadosamente su aplicación y que tenga el suficiente conocimiento de como trabaja Java. Una aplicación en la que se pueda confiar para monitorear su aplicación las 24 horas del día los 365 días del año y que automáticamente se encargue de los problemas cuando se generen. El Java Service Wrapper cuenta con varias propiedades de monitoreo, una de ellas es a habilidad para detectar cuando la JVM se ha bloqueado. Una vez que el Wrapper lo detecta automáticamente reanuda la JVM y mantiene el sistema funcionando con la menor demora posible. Finalmente se puede configurar un email como notificación y enviar al administrador del sistema para asegurarse que todo esta bajo control.

Todo el proceso en la detección de bloqueos, recuperación así como de notificación es controlado por el Wrapper sin la necesidad de que algún humano este operando el sistema para tomar acción a este tipo y muchos otros problemas. Cuando un bloqueo es detectado el Wrapper registrará algo como lo que a continuación se presenta en el archivo de registro de valores:

Ejemplo de Registro de Valores: Bloqueo y Reanudo:
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=0x000000018000749f, pid=2144, tid=2092
jvm 1    | #
jvm 1    | # JRE version: Java(TM) SE Runtime Environment (7.0_40-b43) (build 1.7.0_40-b43)
jvm 1    | # Java VM: Java HotSpot(TM) 64-Bit Server VM (24.0-b56 mixed mode windows-amd64 compressed oops)
jvm 1    | # Problematic frame:
jvm 1    | # C  [wrapper.dll+0x749f]
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    | # Y:\temp\spanish\WrapperSpanish\bin\hs_err_pid2144.log
jvm 1    | #
jvm 1    | # If you would like to submit a bug report, please visit:
jvm 1    | #   http://bugreport.sun.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  | La JVM salió inesperadamente
wrapper  | Iniciando JVM...
jvm 2    | WrapperManager: Inicializando...
jvm 2    | ...

Mientras que el previo mensaje pueda parecer confuso, es la JVM tratando de enviar información sobre el bloqueo. El hecho de que esta salida de datos es enviada a la consola por la JVM a un nivel muy bajo, es imposible que alguna herramienta de registro de valores de Java pueda registrar dicha información. Note que el Wrapper es capaz de capturar el 100% de la salida de datos de la consola de la JVM, asegurándose de mantener toda la información en el archivo de registro de valores. Sin la presencia del Wrapper no sólo su aplicación permanecerá inactiva, pero la explicación de lo que paso será perdida.

Idealmente, cualquier bloqueo debería ser arreglado inmediatamente para evitar problemas similares en el futuro. Sin embargo, como esto es causado por interacciones entre códigos Java válidos y errores en la JVM, puede tomar semanas incluso meses antes que desarrolladores puedan identificar y arreglar el problema.

El Wrapper ayuda a detectar problemas críticos incluyendo:

Descripción Técnica

La detección de bloqueos en el Wrapper esta siempre habilitada, esta propiedad no causa alguna carga adicional en la JVM o el sistema. Se experimenten o no bloqueos, no hay manera de inhabilitar esta propiedad. Sin embargo, es posible controlar lo que el Wrapper hará en respuesta a bloqueos.

Cuando un bloqueo es detectado, el Wrapper primero esperará (por defecto 5 segundos) para permitir que la memoria del sistema y los recursos regresen a la normalidad. De la misma manera que las notificaciones configuradas inicien una nueva instancia JVM para tener su aplicación una vez más en acción sin ningún retraso. Como se describe a continuación es posible inhabilitar esta funcionalidad de reinicio automático si así lo desea.

Probando

Deseamos tenga dificultades para experimentar o tener que reproducir que la JVM se bloquee en su aplicación Java. Para hacer más fácil este tipo de pruebas, la aplicación de ejemplo TestWrapper viene incluida con el Wrapper. Esta aplicación puede ser usada para probar ésta y otras propiedades más.

Por favor ejecutar la aplicación TestWrapper desde una consola desde donde esta descargado el Java Service Wrapper. En Windows ejecute bin\TestWrapper.bat y en plataformas UNIX bin\testwrapper console.

Cuando la aplicación TestWrapper inicie debería ver una simple pantalla GUI con botones del lado izquierdo. Haciendo uso del botón de Violación de Acceso Nativo causará que la JVM sea bloqueada y reiniciada.

Ejemplo de Registro de Valores: Error y Renicio.
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=0x000000018000749f, pid=2144, tid=2092
jvm 1    | #
jvm 1    | # JRE version: Java(TM) SE Runtime Environment (7.0_40-b43) (build 1.7.0_40-b43)
jvm 1    | # Java VM: Java HotSpot(TM) 64-Bit Server VM (24.0-b56 mixed mode windows-amd64 compressed oops)
jvm 1    | # Problematic frame:
jvm 1    | # C  [wrapper.dll+0x749f]
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    | # Y:\temp\spanish\WrapperSpanish\bin\hs_err_pid2144.log
jvm 1    | #
jvm 1    | # If you would like to submit a bug report, please visit:
jvm 1    | #   http://bugreport.sun.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  | La JVM salió inesperadamente
wrapper  | Iniciando JVM...
jvm 2    | WrapperManager: Inicializando...
jvm 2    | ...

Si desea probar esto en su propia aplicación es posible hacerlo llamando WrapperManager.accessViolationNative() para causar un error intencionalmente.

Solución de Problemas

Los reportes de Java de estos errores parecerán no ser de mucha ayuda. Pero cuando se tiene una idea de donde buscar el problema, puede ayudar a resolverlo.

En el ejemplo anterior la JVM nos informa que un reporte detallado sobre el error fue guardado en el disco específicamente en C:\myapp\bin\hs_err_pid856.log. El análisis de estos reportes esta por debajo del enfoque de este documento, pero le recomendamos observe en la Guia de Solución de problemas del sitio web de Oracle. Si desea optar por poner manos a la obra en este tema, entonces este curso de bloqueos enfocado en el análisis de bloqueos en la JVM le será muy útil.

Retrasar Reanudo

Compatibilidad :2.2.9
Ediciones :Edición ProfesionaEdición EstándarEdición de la Comunidad
Plataformas :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/Linux

Cuando un bloqueo es detectado, el Wrapper por defecto espera 5 segundos, ermitiendo que la memoria y recursos del sistema que estaban siendo usados por la JVM bloqueada sea recuperada por el sistema antes de ejecutar una JVM de reemplazo. Si una JVM es ejecutada muy rápido, entonces dependiendo de las razones del bloqueo, la JVM de reemplazo puede experimentar problemas o iniciar lentamente.

El tiempo que el sistema toma para recuperarse depende de un número de factores, incluyendo la carga en general del sistema y el tamaño de la aplicación que estaba siendo usada cuando se suscitó el bloqueo en la JVM. Es posible que este retraso sea más corto, el valor establecido por defecto ha sido comprobado ser muy seguro y eficaz al usarse como tiempo de espera. El retraso antes de iniciar una JVM nueva puede controlarse usando la propiedad wrapper.restart.delay.

Ejemplo de Configuración:Tiempo de espera reiniciando la JVM (5 segundos)
wrapper.restart.delay=5

Inhabilitar Reinicios

Compatibilidad :3.3.4
Ediciones :Edición ProfesionaEdición EstándarEdición de la Comunidad
Plataformas :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/Linux

En muchos casos cuando la JVM sufre bloqueos la mejor opción es reanuda el sistema. Algunas veces es necesario hacer una limpieza manual, o ya sea que otras acciones se necesiten llevar a cabo primero. Cuando esto pasa, la funcionalidad de reanudar el Wrapper puede ser inhabilitada usando la siguiente propiedad wrapper.disable_restarts.automatic.

Ejemplo de Configuración: (Inhabilitar Reanudos)
wrapper.disable_restarts.automatic=TRUE

Respondiendo a Eventos

Compatibilidad :3.3.0
Ediciones :Edición ProfesionaEdición Estándar (No Compatible)Edición de la Comunidad (No Compatible)
Plataformas :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/Linux

En ocasiones cuando una aplicación se congela o se bloquea, un reanudo no siempre es suficiente. Si los archivos temporales no fueron limpiados correctamente y/o la base de datos se encuentra en un estado inestable, la nueva instancia de la aplicación que se genere al reanuda probablemente experimente errores una vez más en un corto periódo. Lo ideal sería que la aplicación fuera diseñada para controlar estos errores de una manera eficaz pero no siempre es posible. En estos casos se necesita una solución para limpiar dichos archivos antes de lanzar una JVM nueva.

El Wrapper da apoyo al hacer uso de Comandos de Eventos. Es posible ordenar al Wrapper que ejecute un comando externo o Secuencia de comandos en diferentes momentos.

Si observa en el registro de depuración de valores en la salida de datos ocasionalmente verá entradas Enqueue Event 'NNN'. Estos muestran el momento en que se disparan los eventos del Wrapper. En caso de que haya un reinicio después de haber detectado que la JVM se congeló, lo que deseamos es lanzar nuestra secuencia de comandos de limpieza antes de lanzar una instancia de JVM nueva. El evento que se usará es jvm_restart.

Por favor cree un archivo por lotes simple y guardarlo en el mismo directorio del Wrapper binario. Este ejemplo simplemente simula una tarea de limpieza de 10 segundos, sabemos que un archivo real resultaría más interesante.

Ejemplo de la Secuencia de comandos: "cleanupTest.bat"
@echo off
echo Limpiando por 10 segundos...
rem usar ping para generar un retraso de 10 segundos.
PING 1.1.1.1 -n 1 -w 10000 >NUL
echo Proceso de Limpieza completo.

Ahora agregue las siguientes propiedades a su archivo wrapper.conf

Archivo de configuración: "wrapper.conf"
wrapper.event.jvm_restart.command.argv.1=cleanupTest.bat
wrapper.event.jvm_restart.command.block=TRUE
wrapper.event.jvm_restart.command.loglevel=INFO

Cuando un bloqueo es detectado, el Wrapper ejecutará el secuencia de comandos configurado y lo bloqueará hasta que la ejecución haya completado.

Ejemplo de la salida de datos:
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  | Esperando 5 segundos antes de lanzar otra JVM. 
wrapper  | Lista de eventos 'jvm_restart'
wrapper  | Comando de Evento 'jvm_restart': Línea de Comando: cleanupTest.bat
wrapper  | Comando de Evento 'jvm_restart': Comando lanzado (pid: 2308), bloqeado por hasta 15 segundos...
Limpiando por 10 segundos...
Proceso de Limpieza completo.
wrapper  | Comando de Evento 'jvm_restart': El comando ha sido completado con un código de salida: 0 
wrapper  | Comando de Evento 'jvm_restart': El comando ha sido completado con un código de salida: 0 Continuando.
wrapper  | Iniciando JVM...

Notificación vía Emails

Compatibilidad :3.3.0
Ediciones :Edición ProfesionaEdición Estándar (No Compatible)Edición de la Comunidad (No Compatible)
Plataformas :WindowsMac OSXLinuxIBM AIXFreeBSDHP-UXSolarisIBM z/Linux

Además de poder ejecutar comandos externos en respuesta a un evento de congelamiento también es posible configurar el Wrapper para enviar Notificaciones vía Email. Dicho email puede ser de una manera simple con la opción de incluir el registro de valores de la salida de datos más reciente.

Una notificación vía email del evento jvm_unexpected_exit puede configurarse de la siguiente manera:

Archivo de Configuración en "wrapper.conf"
wrapper.event.default.email.smtp.host=mail.example.com
wrapper.event.default.email.sender=remitente@ejemplo.com
wrapper.event.default.email.recipient=beneficiario-administrador@ejemplo.com
wrapper.event.jvm_unexpected_exit.email=TRUE
wrapper.event.jvm_unexpected_exit.email.subject=Alerta! su aplicación se ha congelado!
wrapper.event.jvm_unexpected_exit.email.attached_log=TRUE
wrapper.event.jvm_unexpected_exit.email.body=Por favor verifique su estatus.

Esto causará que un email como el que se muestra sea enviado cada vez que la JVM sufra un bloqueo.

Notificación usando emails: jvm_unexpected_exit
Asunto: Alerta! su aplicación se ha congelado!.
Para: beneficiario-administrador@ejemplo.com
De: remitente@ejemplo.com

Notificación de Eventos del Java Service Wrapper 

Host: miservidor
Nombre de aplicación:Testwrapper
         Ejemplo de la aplicación TestWrapper

Evento: jvm_unexpected_exit

INFO   | jvm 1    | 2012/09/13 16:00:00 | ...
INFO   | jvm 1    | 2012/09/13 16:00:00 | # The crash happened outside the Java Virtual Machine in native code.
INFO   | jvm 1    | 2012/09/13 16:00:00 | # See problematic frame for where to report the bug.
INFO   | jvm 1    | 2012/09/13 16:00:00 | #
ERROR  | wrapper  | 2012/09/13 16:00:00 | JVM salió inesperadamente.

También es agradable recibir buenas noticias, la siguiente configuración le dirá al Wrapper que envíe un segundo email cuando la JVM haya sido lanzada y la aplicación este funcionando sin ningún problema. Este par de mensajes son de gran ayuda para mantenerse informado del estado de su servidor y poder decidir si debe estar alerta o disfrutar de la tranquilidad en su hogar.

Archivo de Configuración "wrapper.conf":
wrapper.event.jvm_started.email=TRUE
wrapper.event.jvm_started.email.subject=Buenas noticias! La aplicación se ha recuperado.
wrapper.event.jvm_started.email.maillog=ATTACHMENT

Las notificaciones a través de email y eventos del sistema del Wrapper son muy eficaz y configurables. Por favor visitar la siguiente página para más detalles y Descripción de Eventos.

Servicios de Recuperación

Compatibilidad :3.5.5
Ediciones :Edición ProfesionaEdición EstándarEdición de la Comunidad (No Compatible)
Plataformas :WindowsMac OSX (No Compatible)Linux (No Compatible)IBM AIX (No Compatible)FreeBSD (No Compatible)HP-UX (No Compatible)Solaris (No Compatible)IBM z/Linux (No Compatible)

El Wrapper es confiable y con la suficiente capacidad de controlar bloqueos. Mientras que los procesos del Wrapper han sido comprobados ser muy estables, esta sección cubre como recuperarse en caso de que se presenten bloqueos en los procesos del Wrapper.

El Administrador de Servicios de Windows es responsable de iniciar, detener y monitorear todos los servicios de Windows incluyendo el Wrapper. Es posible configurar el Wrapper para comunicarle al Administrador de Servicios de Windows que hacer cuando se presente un bloqueo. Estas funciones de recuperación pueden ser configuradas usando las propiedades en la sección de Servicios de Recuperación. Para más detalles y ver un ejemplo de esta propiedad visitar wrapper.ntservice.recovery.<x>.

Referencia: Fallos (Crashes)

El Java Service Wrapper proporciona un conjunto completo de propiedades de configuración que le permiten hacer que el Wrapper se adapte exactamente a sus necesidades. Por favor, lea la documentación de las propiedades individuales para ver todas las posibilidades además de los ejemplos mostrados anteriormente.