如何确保EJB计时器仅在Java EE集群环境中创建一次?

时间:2018-03-21 20:47:29

标签: java-ee ejb websphere

我正在开发一个在IBM WebSphere Application Server上的集群Java EE环境中运行的应用程序。我们有一个启动单例bean,它创建一个持久的EJB计时器,我们配置了EJB计时器服务,以便每个集群节点使用相同的数据库表。如何确保2个节点在启动时都不创建持久定时器?我知道如何确保只有一个节点运行超时方法,而不是如何确保计时器不会创建两次。

我们当前正在取消并在启动时使用相同的“名称”重新创建所有计时器,这意味着(如果我理解正确),只要集群节点不同时初始化此bean,那么启动的最后一个节点将清除所有现有计时器并重新创建单个计时器实例。但是,我如何确保避免两个节点同时退出cancelTimer()方法并且都运行TimerService.createTimer()方法的罕见情况,为群集创建2个相同的计时器?

以下是一些示例代码:

@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!");
    }
}

1 个答案:

答案 0 :(得分:0)

在传统的WebSphere Application Server中,如果切换到自动持久性计时器(例如,通过使用@Schedule注释),并且所有集群成员都具有指向同一集群的EJB容器配置作用域调度程序,然后应用程序服务器将负责确保在整个集群中安排一个自动计时器的实例。如果您无法切换到自动持久性计时器并需要继续手动创建它们的方法,一种常见的解决方案是将数据库用作同步点(这实际上是应用程序服务器所做的)。例如,您的start方法可以尝试对数据库条目进行特定更新,指示它已保留计划定时器的权限,并且只有在成功执行此操作时,才会继续安排计时器。