如何在 spring 启动时动态更改 @Scheduler cron 表达式?

How can I change @Scheduler cron expression dynamically in spring boot?

我正在尝试在特定时间呼叫 API。 但有时 api 调用可能会失败,所以我做了一个逻辑来检查 api 调用何时失败。

确认api调用失败后,我想将@Schedulercron表达式从当前的cron表达式更改为15分钟后。

如何动态更改 cron 表达式?

下面是我的API调用代码。

@Scheduled(cron="0 9 19 * * *", zone = "Asia/Seoul")
public void callAPi() throws InterruptedException {

    swrList = new ArrayList<>();
    List<GeoInfo> giList = gs.getGeoXY();
    
    for(GeoInfo gi : giList) {
        
        ShortWeatherReq swr = new ShortWeatherReq(APK.getApiKey(),"1",gi.getX(),gi.getY());
        swr.setBaseDate(); //현재 날짜로 baseDate를 설정하는 메소드를 호출
        swr.setNx(gi.getX()); //x좌표값 저장
        swr.setNy(gi.getY()); //y좌표값 저장
        
        swrList.add(swr); //list에 swr 추가
    }
    
    for(GeoInfo gi : giList) {
        
        ShortWeatherReq swr = new ShortWeatherReq(APK.getApiKey(),"2",gi.getX(),gi.getY());
        swr.setBaseDate(); //현재 날짜로 baseDate를 설정하는 메소드를 호출
        swr.setNx(gi.getX()); //x좌표값 저장
        swr.setNy(gi.getY()); //y좌표값 저장
        
        swrList.add(swr); //list에 swr 추가
    }
    
    //위 객체를 가지고 이제 API를 호출할수 있게 Service에게 전해줘야 함
    sws.setSwrList(swrList);
    
    temperList = sws.callSW(); // API 통신 Service 호출
    
    
    //Confirming API call failure

    if(temperList.isEmpty()) { //온도 리스트가 비어있다면 진입
        logger.warn("TemperList is empty");
        //이제 여기서 메일을 보내주는 서비스를 만들어서 메일 전송을 해줘야 함
        ms.sendErrorMail();
        logger.info("-------------------");
        
        logger.info("API Connection Fail");
    }else {
        logger.info("-------------------");
        
        logger.info("API ConnectionSuccess");
        
        logger.info("-------------------");
        
        //List에 담긴 온도 DB에 저장
        for(int i = 0;i<temperList.size();i++) {
            Temperature temp = temperList.get(i);
            ts.saveTemp(temp);
        }
        
        logger.info("DB Store Success");
    }
}

首先,您应该在 App class 上激活 Spring Retry

@SpringBootApplication
@EnableScheduling
@EnableRetry
public class App {
    // something
}

然后您需要将 @Retryable 添加到您用作 @Scheduled 的方法中。

@Scheduled(cron="0 9 19 * * *", zone = "Asia/Seoul")
// Add this line
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000), value={ApiCallException.class})
public void callAPi() throws InterruptedException {

    swrList = new ArrayList<>();
    List<GeoInfo> giList = gs.getGeoXY();
    
    for(GeoInfo gi : giList) {
        
        ShortWeatherReq swr = new ShortWeatherReq(APK.getApiKey(),"1",gi.getX(),gi.getY());
        swr.setBaseDate(); //현재 날짜로 baseDate를 설정하는 메소드를 호출
        swr.setNx(gi.getX()); //x좌표값 저장
        swr.setNy(gi.getY()); //y좌표값 저장
        
        swrList.add(swr); //list에 swr 추가
    }
    
    for(GeoInfo gi : giList) {
        
        ShortWeatherReq swr = new ShortWeatherReq(APK.getApiKey(),"2",gi.getX(),gi.getY());
        swr.setBaseDate(); //현재 날짜로 baseDate를 설정하는 메소드를 호출
        swr.setNx(gi.getX()); //x좌표값 저장
        swr.setNy(gi.getY()); //y좌표값 저장
        
        swrList.add(swr); //list에 swr 추가
    }
    
    //위 객체를 가지고 이제 API를 호출할수 있게 Service에게 전해줘야 함
    sws.setSwrList(swrList);
    
    temperList = sws.callSW(); // API 통신 Service 호출
    
    
    //Confirming API call failure

    if(temperList.isEmpty()) { //온도 리스트가 비어있다면 진입
        // Add this line
        throw new ApiCallException("API Connection Fail")
    }else {
        logger.info("-------------------");
        
        logger.info("API ConnectionSuccess");
        
        logger.info("-------------------");
        
        //List에 담긴 온도 DB에 저장
        for(int i = 0;i<temperList.size();i++) {
            Temperature temp = temperList.get(i);
            ts.saveTemp(temp);
        }
        
        logger.info("DB Store Success");
    }
}

这里是用@Retryable注解设置backoff参数,设置你想要的下一个运行时。在与BackOffPolicies相关的Spring Retry文档中,做了如下定义。

When retrying after a transient failure, it often helps to wait a bit before trying again, because usually the failure is caused by some problem that can only be resolved by waiting. If a RetryCallback fails, the RetryTemplate can pause execution according to the BackoffPolicy.

您可以找到有关 Spring Retry here 的详细信息。

虽然我的回答没有提供动态更改的 cron 语句,但我希望它能解决您的问题。