【问题标题】:How to make some actions when timeout was reached on transaction如何在事务达到超时时执行一些操作
【发布时间】:2019-07-15 06:58:05
【问题描述】:

我正在维护看起来像这样的代码

@Asynchronous
@TransactionTimeout(value = 1, unit = TimeUnit.HOUR)
public void downloadFile(Long fileId) {

    //This method takes more than 1hour
    service.download(fileId) 

    //this method should be called even when download finished with error
    service.fileDownloadedFinishedNotification(fileId);
}

这只是一个示例代码,我们正在向fileDownloadedFinished 传递我们想要显示的消息等,在其中我们想要将进程标记为错误/成功完成。

正如您在下载时看到的那样,我们可以得到超时,然后fileDownloadedFinishedNotification 将不会被调用,因为事务由于超时而失败。

我正在考虑将通知提取到其他方法并这样调用它:

@Asynchronous
@TransactionTimeout(value = 1, unit = TimeUnit.HOUR)
public Future<String> downloadFile(Long fileId) {

    //This method takes more than 1hour
    service.download(fileId) 
    return new AsyncResult<String>("Test");
}

public void example(){
   long id = 15;
   String msg = "default stuff";

   try {
        msg = downloadFile(id).get();
   }
   catch (Exception e) {
        e.printStackTrace();
   }
   service.fileDownloadedFinishedNotification(fileId, string);

}

但我不确定这是否是个好主意,或者可能还有其他一些功能,我可以在超时时调用它们。类似onTimeout

【问题讨论】:

    标签: java jakarta-ee jboss transactions ejb


    【解决方案1】:

    一些注意事项:

    • 没有简单的方法可以使用侦听器 AFAIK 处理事务超时
    • 注解在后台使用动态代理,它们不会应用于内部调用,您必须从外部调用 downloadFile(在调用者中注入的 bean 上)。
    • 当前事务将在 fileDownloadedFinishedNotification 被调用时中止,因此事务资源(数据库等)上的所有操作都将回滚(您可能必须在专用事务中调用该方法(例如使用 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 注释您的方法。
    • 假设download 方法通过网络检索内容,除非您最后通过专用的JCA adapter 访问此内容,否则事务超时不会引发异常,Transaction reaper 仅将当前事务标记为中止并释放相关资源,但does not interrupt the thread只有后续访问 MANAGED 资源(数据源、JMS 等)才会引发异常
    • 关于最后一点,在与非托管资源交互时,了解当前事务是否仍处于活动状态的唯一方法是使用EJBContext.getRollbackOnly() 定期检查其状态,或对任何托管资源进行虚拟访问。

    【讨论】:

      【解决方案2】:

      有多种方法可以实现您想要的,但正确的实施需要更多关于您对应用程序更改的访问级别的信息。 有很多地方解释了事务传播,但是如果您在 EJB 容器中运行您的应用程序,我将从这里开始:

      https://docs.oracle.com/javaee/6/tutorial/doc/bncih.html

      我会阅读所有章节,但最适合您的情况是此处的容器管理事务:

      https://docs.oracle.com/javaee/6/tutorial/doc/bncij.html

      现在假设您拥有完全访问权限,并且您可以按照我的实现方式更改您的数据库结构:

      • 您正在父事务 T1 中运行服务
      • 在调用下载方法之前,调用另一个服务来记录下载开始和预计完成的最长时间。在 REQUIRED_NEW 事务中执行此操作。这种不耗时的数据库交互将在自治事务 T2 中运行
      • 一旦上述 T2 事务提交,您的下载开始记录就会提交并可供查询
      • 回到父 T1 后开始下载
      • 如果下载成功完成,则将成功记录在您在 T2 中保存的同一记录中。
      • 如果超时,则永远不会记录上述内容,并且数据库仍将显示下载已开始以及预计完成的最长时间
      • 定义一个定期启动并检查下载状态的监控进程。如果超过预期的完成时间,则该监控流程会发出警报或记录失败或触发另一次重试或任何您的业务规则

      希望它有所帮助。抱歉没有编写示例,但我认为您将有足够的开始。

      干杯

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-20
        • 1970-01-01
        相关资源
        最近更新 更多