如何恢复服务器重新启动(即部署)后在内存中创建的计时器任务及其计时器



我正在开发一个应用程序,在该应用程序中,我们需要在事件的[它是应用程序的实体]开始时间事件实体的字段之前处理一些业务逻辑,该字段包含事件的启动时间]

我的应用程序接收这些事件并创建定时器任务,并将该定时器任务[用户定义的]分配给定时器,这样java就可以在给定的时间[x分钟/小时前的事件开始时间]执行。

现在,我面临的问题是,如果服务器/spring引导服务关闭,那么计时器任务和计时器将被破坏,我将无法处理业务逻辑。

我的解决方案方法(效果不佳(:

为了克服这个问题,我尝试了以下逻辑,

  1. 我正在合格事件的新表中添加记录,并且
  2. 标记它们";待处理";在创建计时器任务之前
  3. 一旦它们被处理,我们就将它们标记为";完成">

使用单个服务器实例:现在,如果服务器/服务关闭,我将在新表中使用";待处理";我可以在服务器启动事件中获取并处理这些信息这将适用于单个服务器实例,但我们的基础结构中有多个服务器实例。

多服务器实例的问题:所以主要问题是如何在多个服务器实例中处理这种情况?如何确保只有一个服务器实例会获取记录并执行,因为其他服务器也有可能获取记录并处理它,因此在多个服务器实例中有重复相同事件的定时器任务的机会,并且可能会产生我需要避免的问题。

您可以使用以下"状态";对于存储在表中的事件:

public enum EventState {
READY, 
TAKEN,
DONE
}

生成新事件时,将其添加到表中,并将其标记为READY

当线程选择一个事件进行处理时,它会将其标记为TAKEN,然后开始处理。线程只选择READY事件,不选择其他事件。

当线程完成处理事件时,它会将其标记为DONE(或者简单地将其从表中删除,这取决于您和您是否需要保留已处理的事件(。


如果服务崩溃,当您重新启动它时,主线程(在任何并行线程启动之前(将遍历该表,并检查是否有处于TAKEN状态的线程。

如果是这样,则意味着一个线程已经处理了该事件,但在崩溃之前没有时间完成它。因此,所有这些TAKEN事件将被重新标记为READY,以便可以由该快照中的新线程再次处理。


当然,如果有多个线程读取表,则应该设置一些锁定机制,确保每次只有一个线程可以更新表。

通常您可以使用synchronized方法来完成此操作,例如:

public synchronized Event pickEvent() {
//Search next READY event in the table
//Flag it as TAKEN
//Return it to the thread that should process it
}

上面的方法是synchronized,这保证了每次只有一个线程可以进入该方法,这使您不必担心两个线程同时出现并拾取同一事件。

Vishal让我注意到,您可能有多个JVM在读取同一个表。如果是这种情况,synchronized将无法正常工作,因为它只同步同一JVM中的线程。在这种情况下,您需要在每次有一个线程进入时锁定表,并在每次有线程退出时解锁表。您可以创建一个小型服务来执行表中的读/写操作,而不是直接从线程中读/写表。

最新更新