Creación de temporizadores con el servicio de temporizador EJB para enterprise beans
Puede utilizar los enterprise beans para aprovechar el servicio de temporizador EJB para planificar sucesos basados en tiempo.
Acerca de esta tarea
En soporte de la especificación EJB 3.1, puede crear temporizadores EJB no persistentes. Este producto también soporta la API TimerService expandida para la creación de temporizadores mediante programación. Además, puede configurar el contenedor EJB para crear automáticamente un temporizador cuando se inicie la aplicación.
WebSphere Application Server implementa el servicio de temporizador EJB (Enterprise JavaBeans). En función de las necesidades de la empresa, puede utilizar temporizadores persistentes o no persistentes. Los temporizadores persistentes resultan de utilidad cuando se crea un temporizador para sucesos basados en tiempo que requieren la existencia del temporizador más allá del ciclo de vida del servidor. Los temporizadores persistentes iniciados previamente se inician automáticamente al iniciar el servidor, y persisten tras las operaciones de conclusión y reinicio del servidor. Por ejemplo, puede utilizar temporizadores persistentes para iniciar una aplicación del sistema o enviar una notificación de estado sobre la caducidad del temporizador. Los temporizadores no persistentes son útiles en situaciones que no son críticas, donde las acciones del temporizador se ignoran o se vuelven a realizar sin impactos empresariales negativos, como el sondeo de la temperatura.
Puede crear temporizadores mediante programación. También puede crearlos de forma automática utilizando la anotación @Schedule en la clase de bean o el elemento timer en el descriptor de despliegue de ejb-jar.xml. Al crear automáticamente los temporizadores, puede planificar un temporizador sin confiar en que la invocación de enterprise bean inicie mediante programación un método de creación del servicio de temporizador EJB.
- Temporizadores persistentes
-
Los temporizadores persistentes se implementan como una tarea del servicio de planificador. De forma predeterminada, una instancia del planificador interna (o preconfigurada) se utiliza para gestionar esas tareas, y persisten en una base de datos Apache Derby asociada al proceso del servidor.
Puede realizar personalizaciones básicas en la instancia del planificador interna. Para obtener información sobre la personalización de la instancia del planificador, consulte la información sobre la configuración de un servicio de temporizador.
La creación y cancelación de temporizadores están relacionadas con las transacciones y son persistentes. Si se crea un temporizador como parte de una transacción y dicha transacción se retrotrae más tarde, la creación del temporizador también se retrotrae. Reglas similares rigen la cancelación de un temporizador. Los temporizadores iniciados previamente se conservan tras las operaciones de conclusión y reinicio del servidor de aplicaciones.
- Temporizadores no persistentes
-
EJB 3.1 aumenta el servicio de temporizador EJB de modo que permite temporizadores EJB no persistentes además de los persistentes. Los temporizadores no persistentes tienen muchos de los comportamientos y semántica iguales que los temporizadores persistentes, pero sin la sobrecarga de un almacén de datos. Los temporizadores no persistentes tienen un ciclo de vida distinto al de los temporizadores persistentes. Mientras que los temporizadores persistentes se conservan en las operaciones de conclusión e inicio del servidor de aplicaciones, los temporizadores no persistentes sólo están activos mientras el servidor de aplicaciones está activo. A diferencia de los temporizadores persistentes, no hay mandatos para buscar o cancelar temporizadores no persistentes. Los temporizadores no persistentes se cancelan cuando el servidor de aplicaciones se detiene o no puede mantenerse en estado activo.
Igual que los temporizadores persistentes, la creación y cancelación de los temporizadores no persistentes están relacionadas con las transacciones. Si se crea un temporizador como parte de una transacción y dicha transacción se retrotrae más tarde, la creación del temporizador también se retrotrae. Reglas similares rigen la cancelación de un temporizador.
Puede configurar temporizadores no persistentes para que compartan una agrupación de hebras con los temporizadores persistentes o tener una agrupación de hebras exclusiva que no se comparta con los temporizadores persistentes.
- Temporizadores creados mediante programación
-
Un temporizador persistente creado mediante programación se conserva tras las conclusiones y reinicios del servidor de aplicaciones, a menos que se cancela. El código de aplicación o el administrador del sistema deben encargarse de suprimir un temporizador creado mediante programación que ya no se desee.
Para crear automáticamente un temporizador asociado con el enterprise bean, el bean llama al método getTimerService() en la instancia de contexto aplicable para obtener una referencia al objeto TimerService. El bean también llama a uno de los métodos TimerService, como createTimer, para especificar el temporizador para el bean. Esta instancia de temporizador se asocia ahora con el bean. Los métodos TimerService se describen en la especificación de EJB 3.1. Ahora puede pasar la instancia de temporizador a otro código Java™ como objeto local. Después de que el código Java obtiene la instancia de temporizador, el código puede utilizar cualquiera de los métodos definidos por la interfaz javax.ejb.Timer, como los métodos cancel() o getTimeRemaining().
En un entorno en clúster, un temporizador persistente creado mediante programación puede ejecutarse en cualquier miembro del clúster, pero un temporizador no persistente creado mediante programación sólo se ejecuta en la misma JVM en la que se ha creado.
- Temporizadores creados automáticamente
- La especificación de EJB 3.1 incrementa el servicio de temporizador EJB para permitir la creación automática del temporizador cuando la aplicación se inicia sin confiar en que una invocación de bean inicie mediante programación uno de los métodos de creación del temporizador del servicio de temporizador. Utilice la anotación @Schedule o el elemento del descriptor de despliegue timeout-method para crear temporizadores de forma automática. Los temporizadores creados automáticamente los crea el contenedor como resultado del despliegue de la aplicación.
Avoid trouble: El mandato CancelEJBTimers también cancela los temporizadores creados automáticamente. Cuando se cancelan los temporizadores creados automáticamente se cancelan, la única forma de volver a crearlos es desinstalar la aplicación y volver a instalarla.gotcha
- Temporizadores en un entorno en clúster
-
En un entorno en clúster, un temporizador persistente sólo se ejecuta en un miembro del clúster que no tiene que ser necesariamente el mismo miembro del clúster en el que se ha creado. Un temporizador no persistente se ejecuta en cada miembro del clúster en el que se ha creado: los temporizadores automáticos no persistentes se ejecutan en cada miembro del clúster que contiene el EJB.
Los temporizadores automáticos persistentes se eliminan de su almacén persistente cuando se desinstala el módulo o la aplicación que los contiene. Por consiguiente, no actualice las aplicaciones que utilicen temporizadores automáticos persistentes con la característica Desplegar actualización. Al hacerlo, se desinstala y se reinstala la aplicación mientras el clúster aún está operativo, lo que puede causar anomalías en los casos siguientes:
- Si un temporizador que se ejecuta en otro miembro de clúster se activa después de que se elimine la entrada de la base de datos y antes de que se vuelva a crear la entrada de la base de datos, el temporizador fallará. En este caso, se graba una excepción com.ibm.websphere.scheduler.TaskPending en la captura de datos en primer error (FFDC), junto con el mensaje SCHD0057W, que indica que la información de tarea en la base de datos se ha modificado o cancelado.
- Si el temporizador se activa en un miembro de clúster que no se ha actualizado después de que se hayan actualizado los datos del temporizador en la base de datos, el temporizador podría fallar o causar otros errores si la información nueva del temporizador no es compatible con el código de la aplicación anterior todavía que se sigue ejecutando en el miembro del clúster.
Cuando utilice el servidor proxy en el producto, no defina un planificador en el nivel de célula si dicho planificador se ha configurado como el que se ha de utilizar para el servicio de temporizador EJB. Si lo hace impide que se ejecuten los temporizadores persistentes. Esto puede ocurrir si el servidor proxy obtiene la concesión del planificador. Dado que ninguna aplicación se ejecuta en el servidor proxy, no existe un código de aplicación para manejar los sucesos del temporizador que envía el planificador.
- Reintentos y tiempos de espera excedidos
-
Si utiliza temporizadores EJB, debe entender los conceptos de anomalía, reintento y tiempo de espera excedido.
- Una anomalía es una ejecución de tiempo de espera que se intenta, pero no resulta satisfactoria.
- Un reintento es un intento adicional para ejecutar satisfactoriamente un tiempo de espera que previamente se ha intentado, pero que ha fallado.
- Una ejecución fallida es un tiempo de espera que debería haber intentado pero que no se ha intentado porque el servidor no estaba disponible o estaba ocupado reintentando un tiempo de espera anteriormente fallido.
El comportamiento de reintento refleja:- Número de veces adicionales que el servidor reintenta el tiempo de espera fallido
- Intervalo entre estos reintentos del servidor
El comportamiento de tiempo de espera excedido refleja:- Si el servidor intenta finalmente los tiempos de espera excedidos o no
- Si se acaban intentando tiempos de espera excedidos, cuando se producen esos intentos
- Intervalo entre los intentos de tiempo de espera excedido
Tabla 1. Comportamiento de reintento y tiempo de espera excedido. Comportamiento de reintento y tiempo de espera excedido para temporizadores persistentes y no persistentes. Característica Comportamiento predeterminado Configurable Número de reintentos Tantos como sean necesarios para tener éxito. Los temporizadores persistentes se desactivan temporalmente si se alcanza el umbral de anomalías del planificador en un servidor. Para obtener más información, consulte el tema acerca de la detención de tareas que fallan.
Sí, para los temporizadores no persistentes Intervalo entre reintentos El primer reintento es inmediato. Los reintentos posteriores se producen en el intervalo de sondeo del planificador configurado para los temporizadores persistentes y en el intervalo de reintento configurado para los temporizadores no persistentes.
Sí Recuperación de tiempo de espera excedido Todos los tiempos de espera excedidos se recuperan. No Cuando se recuperen los tiempos de espera excedidos Tanto los temporizadores persistentes como los no persistentes recuperan los tiempos de espera excedidos cuando los reintentos de bloqueo se detienen. Además, los temporizadores persistentes recuperan tiempos de espera excedidos cuando se reinicia un servidor no disponible. No Tiempo de espera siguiente, después de que los reintentos sean satisfactorias y los tiempos de espera excedidos se recuperen A la siguiente hora planificada originalmente. No Las características configurables se configuran en la instancia del planificador para los temporizadores persistentes y en la configuración del temporizador no persistente para los temporizadores no persistentes.
Los siguientes casos de ejemplo muestran cómo influye el comportamiento de reintento y tiempo de espera excedido para los temporizadores persistentes y no persistentes.
Caso de ejemplo de temporizador persistente:
Un temporizador persistente se crea y se configura para ejecutarse por primera vez a las 10:00 y luego ejecutarse cada hora. El planificador que da soporte al temporizador se configura con un intervalo de sondeo de 30 segundos.
El temporizador se ejecuta a las 10:00 y falla porque una base de datos no está disponible. El temporizador se reintenta inmediatamente y se reintenta de nuevo cada 30 segundos cuando se sondea el planificador, y sigue fallando hasta las 12:30. En ese momento, un reintento resulta satisfactorio porque la base de datos vuelve a estar en línea y, por lo tanto el servidor para de reintentar el intento que ha fallado anteriormente.
Ahora, el servidor empieza a procesar los tiempos de espera excedidos. En primer lugar, intenta el tiempo de espera excedido que se debería haber ejecutado a las 11:00, que resulta satisfactorio a las 12:31. Cuando se vuelve a sondear el planificador 30 segundos después, intenta el tiempo de espera excedido que se debería haber ejecutado a las 12:00, que resulta satisfactorio a las 12:32. El servidor está ahora actualizado y el tiempo de espera siguiente se produce a la hora planificada originalmente, a las 13:00, en lugar de una hora después de la última ejecución correcta, que habría sido a las 13:32. En adelante, se mantiene la planificación original. La planificación no se actualiza basándose en la hora del último tiempo de espera satisfactorio.
Caso de ejemplo de temporizador no persistente:
Un temporizador no persistente se crea y se configura para ejecutarse por primera vez a las 10:00 y luego ejecutarse cada hora. Este temporizador no persistente se configura para tener un número de reintentos de 5 y un intervalo de reintento de 30 minutos.
El temporizador se ejecuta a las 10:00 y falla porque una base de datos no está disponible. El temporizador se reintenta inmediatamente y vuelve a fallar. Ahora, después de haber ejecutado el reintento inmediato inicial, el servidor espera durante el intervalo de reintento configurado de 30 minutos entre el reintento siguiente. Se producen reintentos a las 10:30 y a las 11:00, y ambos fallan. Finalmente, se produce el cuarto reintento a las 11:30 y resulta satisfactorio porque la base de datos vuelve a estar en línea.
Ahora, el servidor empieza a procesar los tiempos de espera excedidos. El tiempo de espera planificado originalmente para las 11:00 se ejecuta inmediatamente y resulta satisfactorio a las 11:31. El servidor está ahora actualizado y el tiempo de espera siguiente se produce a la hora planificada originalmente, a las 12:00 (en lugar de una hora después de la última ejecución correcta, que sería a las 12:32).
- Comportamiento de los métodos getNextTimeout y getTimeRemaining
-
Tanto para los temporizadores persistentes como para los no persistentes, el método Timer.getNextTimeout devuelve un objeto java.util.Date que indica la próxima hora a la que está planificada la ejecución del temporizador. Cuando se llama al método getNextTimeout desde un método de devolución de llamada de tiempo de espera para un temporizador basado en un intervalo o en calendario, el método devuelve la siguiente hora planificada; para los temporizadores basados en calendario sin tiempos de espera futuros, el método emite la excepción NoMoreTimeoutsException, tal como lo requiere la especificación EJB 3.1. Cuando se llama al método getNextTimeout desde un método de devolución de llamada de tiempo de espera para un temporizador de una sola acción, el método devuelve la hora planificada originalmente. Si un método de devolución de llamada de tiempo de espera falla y se están realizando reintentos, el método getNextTimeout continúa devolviendo la hora programada originalmente como si la ejecución fallida no se hubiese producido. En todos los casos, el método Timer.getTimeRemaining devuelve la diferencia en milisegundos entre el valor devuelto de getNextTimeout y la hora actual del sistema, lo que puede provocar un número negativo, si la hora de ejecución planificada era pasada.
- Comportamiento de herencia de temporizadores creados automáticamente
-
Los métodos de temporizador automático en una jerarquía de clases de bean provocan la creación de varios temporizadores. El número de temporizadores asociados a un método de temporizador no está determinado por el número de apariciones del método en el código fuente. En lugar de esto, el número de temporizadores asociados a un método de temporizador está determinado por el número de beans con visibilidad para ese método. Por ejemplo:
@Stateless public class Abean { @Schedule(hour=”1”) public void timerMethod1() @Stateless public class Bbean extends Abean { @Schedule(hour=”2”) public void timerMethod2() @Stateless public class Cbean extends Bbean { @Schedule(hour=”2”) public void timerMethod2()
En la jerarquía de clases de bean anterior, se crean tres temporizadores automáticos con el método de devolución de llamada Abean.timerMethod1, uno para cada instancia de bean con visibilidad para ese método. Se crea un temporizador con el método de devolución de llamada Bbean.timerMethod2, y dado que el bean Cbean altera temporalmente este método, sólo se crea un temporizador con el método de devolución de llamada Cbean.timerMethod2.
En el ejemplo anterior, cuando el contenedor procesa el bean Abean, se crea un único temporizador automático, con el método de devolución de llamada Abean.timerMethod1.
Cuando el contenedor procesa el bean Bbean, se crea un temporizador automático con el método de devolución de llamada Bbean.timerMethod2 y se crea otro temporizador automático con el método de devolución de llamada Abean.timerMethod1.
Cuando el contenedor procesa el bean Cbean, se crea un temporizador automático con el método de devolución de llamada CBean.timerMethod2. Se crea otro temporizador automático con el método de devolución de llamada Abean.timerMethod1. No se crea un temporizador para Bbean.timerMethod2 al procesar el bean Cbean. Bbean.timerMethod2 no es visible en la jerarquía de clases de Cbean porque el método Cbean.timerMethod2 lo altera temporalmente.
Considere otro ejemplo como el anterior, si la anotación @Stateless se eliminase de las clases Abean y Bbean, de modo que la clase Cbean es el único EJB. En este caso, los únicos temporizadores automáticos creados serían los visibles para Cbean: uno con el método de devolución de llamada Abean.timerMethod1 y uno con el método de devolución de llamada Cbean.timerMethod2.
Aunque los beans pueden compartir código idéntico en el método de devolución de llamada de un bean heredado, el comportamiento del tiempo de ejecución puede ser polimórfico. Por ejemplo:
public class Employee { @Schedule(hour=”1”, dayOfMonth=”-1”, info = "payroll timer") public void getSalaryIncrease() { printChecks(salary * rate()); } protected float rate() { return (float)1.01; } } public class Manager extends Employee { protected float rate() { return (float)1.15; } } public class Executive extends Manager { protected float rate() { return (float)1.30; } }
En el ejemplo anterior, cada instancia de bean tiene un temporizador automático con el método de devolución de llamada getSalaryIncrease(). Aunque todos los temporizadores comparten el mismo código de devolución de llamada, tenga en cuenta que el índice que cada bean utiliza para calcular el aumento de salario es diferente, debido al polimorfismo. Es decir, los métodos de devolución de llamada de temporizador pueden ser polimórficos de mismo modo que puede serlo cualquier método Java.
Procedimiento
Resultados
Ha configurado automáticamente o mediante programación un temporizador EJB que puede ser persistente o no persistente.