En ocasiones se hace necesario crear un EJB 3.1 que emplee la interfaz Schedule
y normalmente es una tarea muy simple de realizar en Java. Sin embargo, cuando ese aplicativo debe correr en un ambiente de cluster sucede que la tarea se dispara en todos los miembros del cluster y esta situación no siempre es deseable.
En este artículo les explicamos como configurar WebLogic 12c (12.2.1.3.0) para que el EJB se ejecute en únicamente uno de los nodos, manteniendo los beneficios de hacer el deployment en el cluster. Es decir, su alta disponibilidad. Si el nodo donde corre la tarea falla; entonces de manera transparente será ejecutado por otro nodo en el cluster.
EJB con Timer
Nuestro ejemplo en Java es bastante sencillo y no tiene nada diferente a lo dictado en la especificación. Observen que empleamos la anotación Schedule
y establecemos que el proceso debe ejecutarse cada 5 minutos.
@Stateless
public class DemoTimerService implements java.io.Serializable {
private static final Logger LOG = Logger.getLogger(DemoTimerService.class.getName());
@Schedule(month = "*", hour = "*", dayOfMonth = "*", year = "*", minute = "*/5", second = "*", persistent = true)
public void myTimer() {
SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
LOG.log(Level.WARNING, "Timer event: {0}", df.format(new Date()));
}
}
Configuración del WebLogic
Paso 1. Estructuras
El primer paso que tenemos que hacer es configurar el cluster. WebLogic emplea dos tablas para manejar los timers ACTIVE
y WEBLOGIC_TIMER
; estos nombres se pueden cambiar de acuerdo a la normativa de nomenclatura que tengamos establecida. En nuestro caso, lo vamos a dejar de esa manera.
Estas dos tablas deben ser creadas en la base de datos que usaremos para contener esos detalles. Los archivos que tienen el ddl
se encuentran en:
$ORACLE_HOME/wlserver/server/db/oracle/920
, en los archivos scheduler.ddl
y leasing.ddl
Esos scripts son específicos para Oracle, pues corresponden a la base de datos que usaremos de ejemplo; pero además provee los scripts para:
Sybase
MySQL
MSSQL
Informix
DB2
scheduler.ddl
CREATE TABLE WEBLOGIC_TIMERS (
TIMER_ID VARCHAR2(100) NOT NULL,
LISTENER BLOB NOT NULL,
START_TIME NUMBER NOT NULL,
INTERVAL NUMBER NOT NULL,
TIMER_MANAGER_NAME VARCHAR2(500) NOT NULL,
DOMAIN_NAME VARCHAR2(100) NOT NULL,
CLUSTER_NAME VARCHAR2(100) NOT NULL,
USER_KEY VARCHAR2(1000) UNIQUE,
PRIMARY KEY (TIMER_ID, CLUSTER_NAME, DOMAIN_NAME)
);
leasing.ddl
CREATE TABLE ACTIVE (
SERVER VARCHAR2(255) NOT NULL,
INSTANCE VARCHAR2(255) NOT NULL,
DOMAINNAME VARCHAR2(255) NOT NULL,
CLUSTERNAME VARCHAR2(255) NOT NULL,
TIMEOUT DATE,
PRIMARY KEY (SERVER, DOMAINNAME, CLUSTERNAME)
);
Paso 2. Scheduling
Una vez que creamos estas estructuras, procedemos a ir a la consola de administración de WebLogic. Entrando a las propiedades del cluster y seleccionando la opción Scheduling
. Como se aprecia en la siguiente imagen.
Ahí debemos seleccionar el recurso JDBC que tiene la configuración al servidor en donde se crearon las dos estructuras señaladas.
Paso 3. Migration
En la consola, de nuevo en cluster, seleccionamos la opción Migration
y seleccionamos los machines
que pueden emplear para migrar a un servidor que ha fallado. De particular importancia es que se tenga seleccionado Database
y que el recurso JDBC seleccionado sea el mismo que se creo inicialmente. Noten que el nombre por omisión de la tabla es ACTIVE
.
Paso 4. Persistent Stores
En la consola, seleccionamos la opción Persistent Stores
y creamos un nuevo JDBC Store, como mostramos seguidamente.
Ahi debemos seleccionar el datasource (que el mismo que hemos venido usando) y disponer de un nombre lógico. En nuestro caso escribimos storeEJB
Internamente, eso va a crear una tabla WLSTORE
para cada servidor del cluster.
Paso 5. Descriptor
De vuelta en nuestro aplicativo, debemos agregar un archivo descriptor específico para WebLogic. Este se llama weblogic-ejb-jar.xml
y se ve de la siguiente manera:
<?xml version = '1.0' encoding = 'windows-1252'?>
<weblogic-ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-ejb-jar http://xmlns.oracle.com/weblogic/weblogic-ejb-jar/1.7/weblogic-ejb-jar.xsd"
xmlns="http://xmlns.oracle.com/weblogic/weblogic-ejb-jar">
<weblogic-enterprise-bean>
<ejb-name>DemoTimerService</ejb-name>
<stateless-session-descriptor>
<timer-descriptor>
<persistent-store-logical-name>storeEJB</persistent-store-logical-name>
</timer-descriptor>
</stateless-session-descriptor>
</weblogic-enterprise-bean>
<timer-implementation>Clustered</timer-implementation>
</weblogic-ejb-jar>
De ahí es importante tomar nota de:
ejb-name
: Es el nombre del EJBpersistent-store-logical-name
: Debe ser el nombre exacto que definimos en el paso 4.
Y eso es todo; una vez que hacemos deploy de nuestro aplicativo en el servidor veremos que se ejecuta en sólo un nodo del cluster.
El código fuente de este artículo esta disponible en https://github.com/FlechaRoja/EJBTimer
Esperamos que este artículo les sea de utilidad.
Comentarios