如果方法 A 在 Spring 引导中执行时间超过 X 秒,则回退到方法 B

Fallback to methodB if methodA execution takes more than X seconds in Spring Boot

我有一个 Spring 引导应用程序,我有一个 @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 已经停产,我想知道还有哪些其他库可以用于此目的?

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

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

不确定这是否是最佳解决方案,但请检查此问题: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);
}

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

Waits if necessary for at most the given time for the computation to complete, and then retrieves its result, if available.

并按如下方式使用:

  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 秒之前检查。