Clustering and EJB Timer (ENG)

Glassfish Cluster and EJB Timer
G.Morreale

clicca qui per la versione in italiano
Introduction:

One of EJB features is "Timer Service".
It allows you to activate timer for specified periods of time or after certain dates.


This service relies on a embedded Glassfish database.
Go into the console between the connection pool (see JDBC resources) you can see is the connection pool __TimerPool "used by the resource __TimerPool.

This resource is available by default for the target server, then the cluster is not even aware of a db that supports the timer service.

Furthermore, the embedded database is not sufficient as instances of the cluster can not access the db and then know the status of management of the timer service.

Having to deploy on Glassfish cluster that uses an EJB timer service should set up an external db can support transactions and ensure that only one instance to handle the timeout without replicating the events more than necessary.

Steps to configure:

To configure the cluster so that it supports the EJB Timer Service is necessary to follow the following steps

- Create a db (eg TIMER_DB)

- Create in a table using sql scripts that are within $ GLASSFISH_HOME / lib / install / databases
The script mysql is not present you can copy it from here:

CREATE TABLE EJB__TIMER__TBL (
CREATIONTIMERAW bigint NOT NULL,
`` BLOB BLOB,
TIMERID VARCHAR (255) NOT NULL,
CONTAINERID bigint NOT NULL,
OWNERID VARCHAR (255) NOT NULL,
STATE INTEGER NOT NULL,
PKHASHCODE INTEGER NOT NULL,
INTERVALDURATION bigint NOT NULL,
INITIALEXPIRATIONRAW bigint NOT NULL,
LASTEXPIRATIONRAW bigint NOT NULL,
PK_EJB__TIMER__TBL CONSTRAINT PRIMARY KEY (TIMERID)
);

Note: The table name must be uppercase

- Make in "Resource-> Connection Pools" a connection pool that can communicates with the db created.

- Create a resource pointing to the jdbc connection pool you just created.
The resource must be created as the target cluster, to ensure that you can create the resource by clicking on
"Cluster-> name cluster-> Resources-> New-> JDBC Resources"

- Go on the configuration of the cluster (The default is called cluster-config)
select EJB container,
click EJB Timer Service
set in the Timer Datasource jdbc resource name created in previous step.

- Restart the cluster.

Driver XA and Possible problems

To make a good setup needs to be created, as I suggested earlier, a resource jdbc appropriate for the timer.
This choice, however, can create problems when the application that makes use of the timer service simultaneously access a resource jdbc different (for example through hibernate you log on to the connection pool of the db).

In this case the same bean needs to access two resources at once and ensure the ACID properties.
To do this you need a JDBC driver XA-capable

This driver obviously needs to be available in the classpath, eg copying it into the / lib of the domain (default domain1).
(Note: when you update a library, you must restart the application server)

In the case of mysql, the J connector (currently version 5.1.6) is XA compliant.

Besides having a driver with such characteristics is necessary to set the connection pool so that these features are used.
Then in the connection pool should be created as set Resource Type "java.sql.XADataSourcein the field instead DataSourceClassName must set the correct value based on the DBMS used

In the case of this class is mysql
com.mysql.jdbc.jdbc2.optional.MysqlXADataSource


Unfortunately, when the connector J creates problems due to bug:http://bugs.mysql.com/bug.php?id=35489

Consequently when you restart the timer (For example, when you restart an instance of the cluster) will otter the following exception:

INFO: Exception thrown from bean; nested exception is: java.lang.IllegalArgumentException: null source jav ... 

Caused by: java.lang.IllegalArgumentException: null source 
at java.util.EventObject. <init> (EventObject.java: 38) 
at javax.sql.StatementEvent. <init> (StatementEvent.java: 39) 
at 
com.mysql.jdbc.jdbc2.optional.JDBC4PreparedStatementWrapper.close (JDBC4PreparedStatementWr 
apper.java: 70) 
at com.caucho.sql.UserStatement.close (UserStatement.java: 127) 
at com.caucho.sql.UserPreparedStatement.close (UserPreparedStatement.java: 450) 
at org.hibernate.jdbc.AbstractBatcher.closePreparedStatement (AbstractBatcher.java: 534) 

caused by the bug in question.

In order to resolve the issue, pending a new release you can use a nightly build of the connector j providing for the bug fix.
(Note: When you reinstall a library jar in Glassfish must restart).

I settled with that of September 20.


Conclusion

The article was translated from the italian version i'm wrote before.
I translate it with google translate service and after a fast review and some correction I think that it is a bad english too(I'm sorry).
The other article that I wrote directly in english are a little bit better.
however I hope it is helpful.
If you want to correct any sentences please contact me through a comment, don't hesitate!



3 comments:

Joni said...

Here's code that works with MySQL 5.1:

CREATE TABLE EJB__TIMER__TBL (
CREATIONTIMERAW bigint NOT NULL,
`BLOB` BLOB,
TIMERID VARCHAR (255) NOT NULL,
CONTAINERID bigint NOT NULL,
OWNERID VARCHAR (255) NOT NULL,
STATE INTEGER NOT NULL,
PKHASHCODE INTEGER NOT NULL,
INTERVALDURATION bigint NOT NULL,
INITIALEXPIRATIONRAW bigint NOT NULL,
LASTEXPIRATIONRAW bigint NOT NULL,
CONSTRAINT PRIMARY KEY (TIMERID)
);

Giuseppe Morreale said...

thanks Joni!

Danilo Eusepi said...

Ciao, come hai risolto il problema delle eccezzioni?
Io ne ho uno molto simile e mi sta facendo girare la testa