I am working on an application which runs in a clustered Java EE environment on IBM WebSphere Application Server. We have a startup singleton bean which creates a persistent EJB timer and we have the EJB Timer Service configured so that each cluster node uses the same DB tables. How can I make sure that 2 nodes don't both create the persistent timer at startup? I know how to make sure that only one node actually runs the timeout method, but not how to make sure the timer isn't created twice.
We are currently cancelling and recreating all timers with the same "name" on startup, which means (if I understand correctly), that as long as the cluster nodes do not initialize this bean simultaneously, then the last node to startup will clear any existing timers and recreate a single timer instance. However, how do I ensure that we avoid the rare case of 2 nodes both exiting the cancelTimer()
method at the same time and both running the TimerService.createTimer()
method, creating 2 identical timers for the cluster?
Here is some example code:
@Startup
@Singleton
public class Timer{
String timerName = "myTimer";
@Resource
private SessionContext sessionCtx;
@PostConstruct
public void start() {
cancelTimer();
TimerService ts = sessionCtx.getTimerService();
ts.createTimer(new Date(), 60000, timerName);
}
@PreDestroy
public void stop() {
cancelTimer();
}
public void cancelTimer() {
TimerService ts = sessionCtx.getTimerService();
Collection<Timer> timers = ts.getTimers();
for(Timer timer : timers){
if (timer.getInfo().equals(timerName)) {
timer.cancel();
}
}
}
@Timeout
public void timeout() {
System.out.println("timeout!");
}
}
The EJB timer service provides a reliable and transactional notification service for timed events. Timer notifications may be scheduled to occur at a specific time, after a specific elapsed duration, or at specific recurring intervals. You can define callback methods on your EJB to receive these time-based events.
The timer service of the enterprise bean container enables you to schedule timed notifications for all types of enterprise beans except for stateful session beans. You can schedule a timed notification to occur according to a calendar schedule, at a specific time, after a duration of time, or at timed intervals.
Nonpersistent programmatic timers are created by calling TimerConfig. setPersistent(false) and passing the TimerConfig object to one of the timer-creation methods.
In WebSphere Application Server traditional, if you switch to automatic persistent timers (for example, by using the @Schedule annotation) and all of the cluster members have EJB Container configuration that points to the same cluster scoped Scheduler, then the application server will take care of ensuring that exactly one instance of the automatic timer is scheduled across the whole cluster. If you are unable to switch to automatic persistent timers and need to continue with the approach of manually creating them, one common solution would be to use the database as a synchronization point (which is essentially what the application server does). For example, your start method can attempt to make a particular update to a database entry indicating that it has reserved the right to schedule the timer, and only if it succeeds in doing so, proceeds to schedule the timer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With