sourcecode

런타임에 Spring의 @Scheduled fixed delay를 변경하는 방법은 무엇입니까?

codebag 2023. 8. 21. 21:15
반응형

런타임에 Spring의 @Scheduled fixed delay를 변경하는 방법은 무엇입니까?

일정한 간격으로 배치 작업을 실행해야 하며 런타임에 이 배치 작업의 시간을 변경할 수 있습니다.이것 때문에 우연히 발견했습니다.@Scheduled주석이 Spring 프레임워크에서 제공되었습니다.하지만 런타임에 fixedDelay 값을 어떻게 변경해야 할지 모르겠습니다.저는 검색을 좀 해봤지만 유용한 것을 찾지 못했습니다.

스프링 부트에서는 응용 프로그램 속성을 직접 사용할 수 있습니다!

예:

@Scheduled(fixedDelayString = "${my.property.fixed.delay.seconds}000")
private void process() {
    // your impl here
}

속성이 정의되지 않은 경우(예: 기본값이 "60"(초)인 경우)에도 기본값을 지정할 수 있습니다.

@Scheduled(fixedDelayString = "${my.property.fixed.delay.seconds:60}000")

제가 발견한 다른 것들:

  • 메서드는 유효하지 않아야 합니다.
  • 메서드에 매개 변수가 없어야 합니다.
  • 방법은 아마도private

사용할 수 있다는 것을 알게 되었습니다.private편리한 가시성 및 다음과 같은 방식으로 사용:

@Service
public class MyService {
    public void process() {
        // do something
    }

    @Scheduled(fixedDelayString = "${my.poll.fixed.delay.seconds}000")
    private void autoProcess() {
        process();
    }
}

존재private예약된 메서드는 서비스에 대해 로컬일 수 있으며 서비스의 API에 포함되지 않을 수 있습니다.

또한, 이 접근 방식은 다음을 가능하게 합니다.process()값을 반환하는 방법, 즉@Scheduled방법이 아닐 수도 있습니다.예를 들어, 당신의process()방법은 다음과 같습니다.

public ProcessResult process() {
    // do something and collect information about what was done
    return processResult; 
}

처리 중 발생한 작업에 대한 정보를 제공합니다.

를 사용할 수 있습니다.Trigger다음 실행 시간을 동적으로 설정합니다.

자세한 내용은 프로그래밍 방식으로 Spring 작업 예약에 대한답변참조하십시오.

인터페이스를 만듭니다.

    public abstract class DynamicSchedule{
        /**
         * Delays scheduler
         * @param milliseconds - the time to delay scheduler.
         */
        abstract void delay(Long milliseconds);

        /**
         * Decreases delay period
         * @param milliseconds - the time to decrease delay period.
         */
        abstract void decreaseDelayInterval(Long milliseconds);

        /**
         * Increases delay period
         * @param milliseconds - the time to increase dela period
        */
        abstract void increaseDelayInterval(Long milliseconds);
}

다음으로 스프링 컨텍스트 프로젝트에서 org.springframework.scheduling에 있는 트리거 인터페이스를 구현하겠습니다.

import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;

import java.util.Date;
import java.util.concurrent.ScheduledFuture;

public class CustomDynamicSchedule extends DynamicSchedule implements Trigger {

    private TaskScheduler taskScheduler;
    private ScheduledFuture<?> schedulerFuture;

    /**
     * milliseconds
     */
    private long delayInterval;

    public CustomDynamicSchedule(TaskScheduler taskScheduler) {
        this.taskScheduler = taskScheduler;
    }


    @Override
    public void increaseDelayInterval(Long delay) {
        if (schedulerFuture != null) {
            schedulerFuture.cancel(true);
        }
        this.delayInterval += delay;
        schedulerFuture = taskScheduler.schedule(() -> { }, this);
    }

    @Override
    public void decreaseDelayInterval(Long delay) {
        if (schedulerFuture != null) {
            schedulerFuture.cancel(true);
        }
        this.delayInterval -= delay;
        schedulerFuture = taskScheduler.schedule(() -> { }, this);
    }

    @Override
    public void delay(Long delay) {
        if (schedulerFuture != null) {
            schedulerFuture.cancel(true);
        }
        this.delayInterval = delay;
        schedulerFuture = taskScheduler.schedule(() -> { }, this);
    }

    @Override
    public Date nextExecutionTime(TriggerContext triggerContext) {
        Date lastTime = triggerContext.lastActualExecutionTime();
        return (lastTime == null) ? new Date() : new Date(lastTime.getTime() + delayInterval);
    }
}

이제 구성:

@Configuration
public class DynamicSchedulerConfig {
    @Bean
    public CustomDynamicSchedule getDynamicScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.initialize();
        return  new CustomDynamicSchedule(threadPoolTaskScheduler);
    }
}

및 용도:

@EnableScheduling
@Component
public class TestSchedulerComponent {

    @Autowired
    private CustomDynamicSchedule dynamicSchedule;

    @Scheduled(fixedDelay = 5000)
    public void testMethod() {
        dynamicSchedule.delay(1000l);
        dynamicSchedule.increaseDelayInterval(9000l);
        dynamicSchedule.decreaseDelayInterval(5000l);
    }

}

이를 위해 스프링 표현 언어(SpEL)를 사용할 수도 있습니다.

@Scheduled(fixedDelayString = "#{@applicationPropertyService.getApplicationProperty()}")
public void getSchedule(){
   System.out.println("in scheduled job");
}

@Service
public class ApplicationPropertyService {

    public String getApplicationProperty(){
        //get your value here
        return "5000";
    }
}

AFAIK Spring API는 트리거를 변경하는 데 필요한 내부에 액세스할 수 없도록 합니다.대신 수동으로 콩을 구성할 수 있습니다.

<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
    <property name="jobDetail" ref="jobDetail" />
    <property name="startDelay" value="10000" />
    <property name="repeatInterval" value="50000" />
</bean>

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="simpleTrigger" />
        </list>
    </property>
</bean>

SchedulerFactoryBean에 설명된 대로:

런타임에 작업을 동적으로 등록하려면 이 SchedulerFactoryBean에 대한 참조를 사용하여 Quartz Scheduler(쿼츠 스케줄러)에 직접 액세스합니다.org.quartz.Scheduler이렇게 하면 새 작업과 트리거를 생성하고 전체 스케줄러를 제어 및 모니터링할 수 있습니다.

저도 같은 문제를 다루었습니다.우리는 런타임에 cron 표현식을 변경하고 서비스를 다시 예약해야 합니다.그래서 다음과 같은 것이 있어야 합니다.

  • 재컴파일 안 함
  • 재배치 없음
  • 다시 시작 안 함

신청서의.저는 인기 있는 솔루션을 모두 검사했지만 그 중 2개만 모든 요구 사항을 충족합니다.

SchedulingConfigurer 접근 방식의 단점은 풀 기반이라는 것입니다. 즉, 서비스의 비즈니스 로직이 실행될 때마다 스케줄링 구성이 풀됩니다.일반적으로 나쁜 것은 아니지만 구성이 거의 변경되지 않고 실행 간격이 짧으면 불필요한 요청이 많이 발생합니다.

사용자 지정 솔루션의 단점은 코딩이 조금 더 필요하지만 푸시 기반이며 구성 변경에 대응하여 불필요한 요청/호출이 수행되지 않는다는 것입니다.

언급URL : https://stackoverflow.com/questions/15250928/how-to-change-springs-scheduled-fixeddelay-at-runtime

반응형