Gestión de hilos dentro de una aplicación web de Tomcat.
Buenos días,
El escenario que tenemos es el siguiente: tenemos una aplicación web, que a su vez tiene un servlet que se carga al inicio, que a su vez ejecuta dos hilos.
Dichos hilos ejecutan una consulta contra una base de datos, que lo que hace es buscar información sobre si existen o no existen nuevos registros. En caso de existir, realiza una serie de acciones sobre los mismos.
Dichos hilos se ejecutan cada un intervalo corto de tiempo, de manera continúa.
Pueden ser detenidos desde un parámetro de base de datos, que indica si están activos o no. Cuando el parámetro no está activo, el hilo es conocedor de ello y entonces se detiene.
El objetivo es realizar un despliegue de la aplicación haciendo uso de Tomcat7. Tenemos la aplicación web ya desplegada en Tomcat7, y dicha aplicación está en ejecución, estando los hilos en ejecución. La pregunta es, ¿cómo realizado la subida de la nueva versión de la aplicación que ya tengo en un fichero war?
Por favor, ser explícitos en la respuesta.
Muchas gracias por vuestra participación,
Reader Comments (12)
Si está bien programado no debería haber ningún problema.
Te adjunto un ejemplo que se explica por sí solo: Dos tareas que escriben en dos archivos distintos con cadencia distinta. La clave es liberar los recursos de forma ordenada.
http://pastebin.com/3nPYQFYu
Chao!
Lo que debes hacer es crear una nueva clase que implemente la interfaz ServletContextListener y agregarla tu aplicación. En esta nueva clase debes agregar una implementación del método contextDestroyed() que alerte a tus threads y les indique que deben terminar, porque la aplicación ya a volver a ser desplegada.
La lógica de los threads ahora no sólo debe depender del valor del parámetro en la base de datos, sino de un boolean que debe ser posible modificar desde el método contextDestroyed() que debes implementar, para que sea posible detenerlos desde ahí.
Un ejemplo de como implementar este Listener está acá:
http://www.javabeat.net/2009/02/servletcontextlistener-example/
Aunque el test que sigue no tiene relación directa con tu cuestión, tal vez ayude a entender lo que sucede.
public class ThreadTest {
private static int contador;
private static ReentrantLock lock;
private static Condition lockCondition;
private static boolean exit;
public static void main(String[] args) {
lock = new ReentrantLock();
lockCondition = lock.newCondition();
final ExecutorService pool = Executors.newCachedThreadPool();
pool.submit(new Runnable() {
@Override
public void run() {
while (true) {
lock.lock();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("tic, tac... " + contador);
contador++;
if (contador > 5) {
exit = true;
lockCondition.signalAll();
}
} catch (InterruptedException ex) {
Logger.getLogger(ThreadTest.class.getName()).log(Level.SEVERE, null, ex);
} finally {
lock.unlock();
}
}
}
});
lock.lock();
try {
while (!exit) {
try {
lockCondition.await();
} catch (InterruptedException ex) {
Logger.getLogger(ThreadTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
} finally {
lock.unlock();
}
pool.shutdownNow();
System.exit(contador);
}
}
Muchas gracias a todos, profundizaré un poco más en el tema de los hilos.
Un saludo amigos
No acabo de entender qué tienen que ver los hilos con subir una nueva versión de la aplicación.
Si está bien programado, los Threads han de ser detenidos cuando el contexto de la aplicación web se para, y han de arrancar cuando el contexto arranque. Sin más.
Y como dice Denis, la mejor opción es un ServletContextListener.
Y eso de que los Threads solo se detengan tras leer un flag de la BDD... es una receta para dar problemas. Si alguna vez la conexión a la BDD se pone tonta... :)
Hola Gualdefu, gracias por tu aportación.
Sobre guardar el estado de ejecución de los hilos (1 -> en ejecución, 0 -> parado) en base de datos, ¿conoces una forma más apropiada, para poder persistir en el tiempo el estado de una sesión ejecutada por el usuario?
Quiero decir, el usuario entra en la aplicación, habilita los hilos, y más adelante, sale de la sesión. En la siguiente sesión, queremos que los hilos sigan habilitados.
Segundo caso: el usuario entra en la aplicación, deshabilita los hilos, y sale de la sesión. En este caso, cuando vuelva a entrar, queremos que los hilos aparezcan deshabilitados.
Un saludo y gracias por comentar,
Jaime
Una opción es usar el contexto, que es lo que "persiste" mientras la aplicación está en marcha. Y al arrancar y/o parar el contexto, entonces puedes consultar/guardar el estado en algo más persistente, como el S.O (algún fichero), la BDD o combinaciones de ambos.
Así no tienes que consultar la BDD cada vez y te proteges contra fallos transitorios, frecuentes en aplicaciones "de vida larga".
Hola Guatdefu, gracias por tu comentario.
En este caso, la aplicación funciona de la siguiente manera.
1) Arranca.
2) Lee de BD.
3) Si el campo correspondiente indica "habilitado" arranca los hilos, en caso de estar "deshabilitado", no los arranca.
4) Una vez en ejecución, existe un apartado visual que permite "habilitar / deshabilitar" los hilos. Simplemente, lo que hace es parar o arrancar los hilos (según el caso) y almacenar dicha información en BD para que, en la siguiente ejecución, se almacene el estado de la aplicación.
En la actualidad, hay varias maneras de persistir el estado, de manera que trascienda al concepto de sesión del usuario:
1) A nivel de usuario, podemos hacer uso del concepto de preferences de HTML5, que permite guarar información persistida en el navegador. Si queremos trascender al conpceto de persistencia clave - valor, existe una base de datos relacional incorporado en HTML5 que nos permitiría guardar información más compleja.
2) La siguiente posibilidad es almacenar un estado centralizado, para ello, es necesario trascender de memoria (que termina al terminar la ejecución de la aplicación) y hacer uso de información persistida, que puede ser un forma de ficheros, y un concepto más evolucionado, hacer uso de base de datos.
Dime, con respecto a la aplicación, en el caso concreto que te comento, ¿cómo resolverías este problema?
Muchas gracias,
Jaime.
Lo de almacenarlo en el cliente... la verdad no le veo mucho sentido, ya que el proceso afectado son Threads en el servidor... Yo lo veo como una tarea típica del servidor, independiente del usuario/navegador que se use para acceder.
Hola Guatdefu, gracias por tu aportación. Estoy de acuerdo en que parece, en este caso, poco conveniente hacer uso de almacenaje de valores en el cliente, aunque sí podemos acceder desde los propios servlets (cosa que desconozco a día de hoy), sería quizá una buena opción.
En un post anterior, comentaste que te parecía peligroso hacer uso de base de datos. después de los datos que te he dado, ¿harías uso en este caso de base de datos?
Un saludo,
Peligroso, peligroso no es. Lo que quería decir es que comprobar cada vez contra la BDD si el Thread ha de seguir ejecutándose o no me parece innecesario y muy dependiente de la conexión a la BDD, que quieres que no, al final Murphy cae.
Usar la BDD no tiene nada de malo, mientras no abuses, así que simplemente usándola para guardar los cambios de estado y recuperar el valor al arrancar sería suficiente y sin excesiva dependencia. IMHO.
Pero vamos, quizá es por mi entorno, pero tarde o temprano en el algún momento las conexiones se pierden (sea alguien toca algo en redes, una tormenta tontea las comunicaciones, un fallo hard el algún sitio) y a veces las conexiones se quedan tontas de verdad (dado que algunos driver JDBC los timeout no los controlan bien del todo) y si te pilla en fin de semana o vacaciones, pues te la puede liar. Así que si por "el mismo precio" puedes hacerlo sin depender de la BDD, pues mejor.
Completamente de acuerdo Guatdefu.
Muchas gracias a todos por vuestros comentarios, me alegra ver el nivel de participación y técnico.
La otra opción de persistencia, siendo más "simple" que usar una base de datos, es persistir la información contra un fichero, pero bueno, ya nos meteríamos a destripar muchas cosas y tampoco es plan. Aceptemos base de datos como estándar de persistencia :)
Un saludo!