【问题标题】:Fallback to methodB if methodA execution takes more than X seconds in Spring Boot如果在 Spring Boot 中 methodA 执行时间超过 X 秒,则回退到 methodB
【发布时间】:2019-05-21 04:12:45
【问题描述】:

我有一个 Spring Boot 应用程序,我有一个 @Service,它很重,可以执行 0.5 到 5 秒。如果执行时间超过 1 秒,我希望它停止执行并回退到回退方法。

/// entry point
public String longLatingMethod(Payload payload) {
    /// long lasting operation that can take up to 5 seconds
    return value; 
}

// I want this method to be executed if `longLatingMethod` takes more than 1 second to execute.
public String fallbackMethod(Payload payload) {
    return defaultValue;
}

现在我已经用Hystrix 框架实现了它,但是由于Hystrix 已经停产,我想知道还有哪些其他库可以用于此目的?

【问题讨论】:

    标签: java spring-boot hystrix


    【解决方案1】:

    您必须在某种线程中运行您的任务,以便您可以继续执行并等待(一定的毫秒数)该进程完成。如果它没有在分配的时间内完成,则中断主要任务并运行备份任务。请注意,您的主要任务必须检查它是否被中断,阻塞操作通常已经检查了这一点,并且在中断时将停止阻塞。

    public static void main(String[] args){
        Thread t = new Thread(() -> {
            // your long running task here...
            System.out.println("running primary task");
    
            // simulate it taking too long...
            // will need to check if it is interrupted if you want to terminate it sooner
            try {
                Thread.sleep(60000);
            } catch (InterruptedException e) {
                System.out.println("primary task interrupted");
            }
        });
        t.start();
    
        // one second threshold
        try { t.join(1000); } catch (Exception e) {}
    
        if (t.isAlive()) {
            // if the primary task is still running interrupt it
            t.interrupt();
    
            // run your backup task
            System.out.println("running backup task");
            // ...
            System.out.println("backup task completed");
        } else {
            System.out.println("primary task completed");
        }
    }
    

    输出:

    running primary task
    running backup task
    primary task interrupted
    backup task completed
    

    【讨论】:

      【解决方案2】:

      不确定这是否是最佳解决方案,但请检查以下问题:Java: set timeout on a certain block of code?

      并在超时捕获块中添加回退

      final Runnable stuffToDo = new Thread() {
        @Override 
        public void run() { 
          /* Do stuff here. */ 
        }
      };
      
      final ExecutorService executor = Executors.newSingleThreadExecutor();
      final Future future = executor.submit(stuffToDo);
      executor.shutdown(); // This does not cancel the already-scheduled task.
      
      try { 
        future.get(1, TimeUnit.Seconds); 
      }
      catch (InterruptedException ie) { 
        /* Handle the interruption. Or ignore it. */ 
      }
      catch (ExecutionException ee) { 
        /* Handle the error. Or ignore it. */ 
      }
      catch (TimeoutException te) { 
          return fallbackMethod(payload);
      }
      

      【讨论】:

      • 我自己没有否决您的答案,但您最好在答案中包含一些引用的代码。这样,如果该答案被删除/更新,您的答案就会不言自明。
      【解决方案3】:

      您可以使用 Future 特别是 V get(long timeout, TimeUnit unit) 方法:

      如有必要,最多等待给定的时间以完成计算,然后检索其结果(如果可用)。

      并按如下方式使用:

        Callable<String> task = () -> {
          ...
        };
      
         public Future<String> myMethod() {
           return Executors.submit(task);
         }
      
         public String fallBackMethod() {
            ...
         }
      
         String value = null;
         try {
            Future<String> result = myMethod.get(1, TimeUnit.SECONDS);
            value = result.get();
         } catch (TimeoutException e) {
            value = fallBackMethod();
         }
      

      请注意,如果您不修改该方法并定期检查它是否已完成,则您无法在方法启动后停止执行该方法,但通常您不能,例如,如果您要求在数据库上查询,查询需要 5 秒,您无法在 5 秒之前检查。

      【讨论】:

      • 听起来像是一个解决方案。我不需要停止原来的方法,所以一切都好。为什么这个答案被否决了?
      • @SergeiLedvanov 不知道 :-D 但如果它有效,请将其标记为正确的解决方案并投票。谢谢
      • 感觉应该可以,不过还没有测试过。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-03
      • 1970-01-01
      • 2011-03-04
      • 2022-01-11
      • 2019-03-25
      • 2020-04-29
      • 2013-04-01
      相关资源
      最近更新 更多