spring 如何利用布尔标志在函数中实现重试机制

3wabscal  于 2023-03-22  发布在  Spring
关注(0)|答案(1)|浏览(151)

我想做的事:

我想为函数checkExpiryForADate实现一个重试机制。在函数checkExpiryForADate中有一个部分我们将调用externalService.getRecord,它可能返回一个空列表。
如果是这种情况,我想每隔10分钟重新运行一次该函数,直到它不返回空列表(一旦externalService.getRecord在运行checkExpiryForADate时不返回空列表,我们就不会在计划的时间段内(从上午7点到上午9点)再运行它)
为了实现重试机制,我将checkExpiryForADate修改为如下所示

我尝试过的:

@Scheduled(cron = "${scheduler: */10 7-8 * * MON-FRI}")
public void loadAndCheckExpiry() {
  boolean checkedRecordIsAvailable = false; //initialise the flag as false
  if (!checkedRecordIsAvailable) { //if flag is false, run `checkExpiryForADate`
      checkedRecordIsAvailable = checkExpiryForADate(dateService.today()); //update flag's value
  }
}

public boolean checkExpiryForADate(LocalDate asOf)
{
    Collection<Product> listOfProducts = productService.getProducts(asOf)

    for (Product product : listOfProducts) {

        //What I want to do here is that: if 1 of the products couldn't get `expiryRecord` in the `checkExpiry` function, 
        then we return false for the this `checkExpiryForADate` function

        if (!checkExpiry(product, asOf) {
            //get out of the for loop
            return false;
        }
    }

private boolean checkExpiry(Product product, LocalDate asOf) {
    //code to perform some operations - omitted

    List<Pair<ZonedDateTime, Double>> expiryRecords = new ArrayList<>(externalService.getRecord());
    if (expiryRecords.isEmpty()) {
        return false;
    }
    
    //code to perform some operations - omitted
    return true;
}

我的代码的问题:

1.在loadAndCheckExpiry函数中,每当运行函数时,checkedRecordIsAvailable将再次初始化为false。我是否应该将标志放在loadAndCheckExpiry之外?如果是这样,它可以在7-8AM(计划)之间更新为true-但我需要在第二天每天再次将其设置为false。
1.使用下面的代码checkedRecordIsAvailable = checkExpiryForADate(dateService.today());更新标志是否正确?(当checkExpiryForADate返回true时,布尔值checkedRecordIsAvailable确实会被更新?
此外,有一个警告redundant assignment说,值checkExpiryForADate(dateService.today())分配给checkedRecordIsAvailable是永远不会使用.但我认为我使用它在一个if语句?
1.在checkExpiryForADate中,如果对于checkExpiry(product, asOf)中的乘积的任何一个1返回false,那么我想跳出for循环,直接为checkExpiryForADate返回false。这是正确的方法吗?
1.总的来说,我觉得我的代码很繁琐,我想知道有没有更优雅的方法来做?
任何帮助将不胜感激,提前感谢。

nx7onnlm

nx7onnlm1#

我认为这个问题类似于How to implement retry mechanism with exception and try catch,这里有一个可能的解决方案:
loadAndCheckExpiry函数之外,定义lastSucess而不是checkedRecordIsAvailable作为检查标志:

private Long lastSuccess = null;

loadAndCheckExpiry

@Scheduled(cron = "${scheduler: */10 7-8 * * MON-FRI}")
public void loadAndCheckExpiry() {
    if (!sameDate(lastSuccess, System.currentTimeMillis())) { //if flag is false, run `checkExpiryForADate`
        checkExpiryForADate(dateService.today()); //update flag's value
    }
}

checkExpiryForADate,如果checkExpiry为任何产品返回false,则中断循环,如果每个产品都通过checkExpiry,则将lastSuccess设置为当前时间:

private void checkExpiryForADate(LocalDate asOf){
    Collection<Product> listOfProducts = productService.getProducts(asOf);
    for (Product product : listOfProducts) {
        if (!checkExpiry(product, asOf)) return;
    }
    lastSuccess = System.currentTimeMillis();
}

checkExpiry

private boolean checkExpiry(Product product, LocalDate asOf) {
    // your code ...
    List<Pair<ZonedDateTime, Double>> expiryRecords = new ArrayList<>(externalService.getRecord());

    // your code ...
    return !expiryRecords.isEmpty();
}

sameDate用于检查两个Long值是否在同一日期内,如果其中一个值是null,则返回false

private Boolean sameDate(Long d1, Long d2){
    if(d1 == null || d2 == null) return false;
    Calendar cal1 = Calendar.getInstance();
    Calendar cal2 = Calendar.getInstance();
    cal1.setTimeInMillis(d1);
    cal2.setTimeInMillis(d2);
    return cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) &&
                            cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
}

希望能帮上点忙。

相关问题