【问题标题】:is it possible to create Singleton non-persistent ejb timer?是否可以创建单例非持久 ejb 计时器?
【发布时间】:2021-04-20 20:21:06
【问题描述】:

我正在使用带有@schedule 注释的EJB 自动计时器服务。但是我需要以下帮助。

我需要一个单例时间服务(仅在集群中的一个节点上执行),但不想在服务器重启或崩溃期间执行错过的计时器。

我阅读了很多文章,但每个人都在提到持久计时器以在集群环境中实现单例行为。

我的代码:

@Singleton
@Startup
public class DataService {
     @Schedule(second="*/10", minute="*", hour="*", persistent=false)
     public void xxxFetch() {
         // business logic
     }
}

有没有办法用非持久定时器实现单例服务?

【问题讨论】:

    标签: java ejb wildfly ejb-3.1 timertask


    【解决方案1】:

    此行为在 EJB 3.2 规范中定义(第 13.2.2、13.2.3、13.2.4 和 13.4.4 节)。

    有两种类型的计时器,自动创建的计时器(带有注释),或以编程方式注释的计时器(使用TimerService)。两者都可以是持久的或非持久的。

    • 持久性计时器(自动或以编程方式创建)将仅在一个节点中运行。
    • 非持久性自动创建的计时器将在集群中的每个节点上运行。
    • 以编程方式创建的非持久计时器将仅在它们创建的节点上运行。

    因此,要使用非持久计时器实现单例服务,您需要设置某种配置,或者在其中一个节点上触发请求,以便它以编程方式创建计时器。

    但请注意,如果该节点发生故障,计时器服务将不会执行。

    使用新的Concurrency for Java EE 规范在ManagedScheduledExecutorService 中调度任务可以实现相同的行为。但是 IMO 对使用 TimerService 以编程方式创建非持久计时器没有任何优势。恰恰相反:创建计时器是事务性操作,而调度任务则不是。

    不过,Wildfly 功能可以满足您的需求:High Availability Singleton Deployments

    您可以将模块定义为单例部署。该模块部署到集群中,但仅在一个节点上处于活动状态。如果该节点发生故障,则在另一个节点中激活该模块。

    因此,您可以将您的 EJB 与自动或以编程方式创建的计时器放在一个单例模块中,这样您就可以在一个节点中执行并获得高可用性。

    【讨论】:

    • 任何替代方案,例如使用 ManagedScheduledExecutorService?
    • 使用ManagedSheduledExecutorService,您可以实现与使用TimerService 以编程方式创建的非持久计时器的相同行为。但是 IMO 它没有提供任何优势,恰恰相反:创建计时器是事务性的,而调度任务不是。
    • 我添加了有关可满足您需求的 Wildfly 功能的信息:HA 单例部署
    • HA 单例部署适用于整个 ear/war 文件。我们如何在 EAR 中实现单个服务的单例服务?
    • 根据wildfly doc,你不能。 “此描述符可以应用于任何部署类型,例如 JAR、WAR、EAR 等,但 EAR 中的子部署除外。”您需要将 EJB 提取到单独的 JAR 中,并将该 JAR 部署为单例。