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

Jaa*_*awn 6 websphere ejb jakarta-ee

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

我们目前正在启动时取消并重新创建所有具有相同“名称”的计时器,这意味着(如果我理解正确的话),只要集群节点没有同时初始化这个 bean,那么最后一个启动的节点将清除任何现有的计时器并重新创建单个计时器实例。但是,我如何确保我们避免 2 个节点同时退出该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!");
    }
}
Run Code Online (Sandbox Code Playgroud)

njr*_*njr 3

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