【问题标题】:How do you make sure that an EJB timer is only created once in a Java EE clustered environment?如何确保 EJB 计时器在 Java EE 集群环境中只创建一次?
【发布时间】:2018-03-21 20:47:28
【问题描述】:

我正在开发一个在 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!");
    }
}

【问题讨论】:

标签: jakarta-ee ejb websphere


【解决方案1】:

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

【讨论】:

  • 啊,谢谢你的数据库建议。我认为这是我将采取的路线,因为如果您使用 @Schedule,计时器会在部署期间创建,如果需要,管理它们会更加麻烦。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-07
  • 2020-12-04
  • 2010-10-24
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
  • 2017-04-08
相关资源
最近更新 更多