복붙노트

[SPRING] @Scheduled 주석을 사용하여 시작된 예약 된 작업을 중지하는 방법은 무엇입니까?

SPRING

@Scheduled 주석을 사용하여 시작된 예약 된 작업을 중지하는 방법은 무엇입니까?

Spring Framework의 @Scheduled 주석을 사용하여 간단한 예약 된 작업을 만들었습니다.

 @Scheduled(fixedRate = 2000)
 public void doSomething() {}

이제 더 이상 필요하지 않을 때이 작업을 중단하고 싶습니다.

이 방법의 시작 부분에 하나의 조건 플래그를 확인하는 대안이있을 수 있지만이 방법의 실행은 중단되지 않습니다.

@Scheduled 작업을 멈추기 위해 Spring이 제공하는 것이 있습니까?

해결법

  1. ==============================

    1.ScheduledAnnotationBeanPostProcessor를 제공하고 스케줄링을 중지해야하는 bean에 대해 postProcessBeforeDestruction (Object bean, String beanName)을 명시 적으로 호출하십시오.

    ScheduledAnnotationBeanPostProcessor를 제공하고 스케줄링을 중지해야하는 bean에 대해 postProcessBeforeDestruction (Object bean, String beanName)을 명시 적으로 호출하십시오.

    private final Map<Object, ScheduledFuture<?>> scheduledTasks =
            new IdentityHashMap<>();
    
    @Scheduled(fixedRate = 2000)
    public void fixedRateJob() {
        System.out.println("Something to be done every 2 secs");
    }
    
    @Bean
    public TaskScheduler poolScheduler() {
        return new CustomTaskScheduler();
    }
    
    class CustomTaskScheduler extends ThreadPoolTaskScheduler {
    
        @Override
        public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
            ScheduledFuture<?> future = super.scheduleAtFixedRate(task, period);
    
            ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task;
            scheduledTasks.put(runnable.getTarget(), future);
    
            return future;
        }
    
        @Override
        public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
            ScheduledFuture<?> future = super.scheduleAtFixedRate(task, startTime, period);
    
            ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task;
            scheduledTasks.put(runnable.getTarget(), future);
    
            return future;
        }
    }
    

    Bean에 대한 스케줄링을 중지해야 할 때 맵을 검색하여 해당 Future를 가져 와서 명시 적으로 취소 할 수 있습니다.

  2. ==============================

    2.이 질문에는 다소 모호한 점이 있습니다.

    이 질문에는 다소 모호한 점이 있습니다.

    내 최고의 추측은 복구 가능한 방식으로 동일한 앱에서 발생할 수있는 조건을 사용하여 작업을 종료하려고하는 것입니다. 나는이 가정에 기초하여 대답하려고 노력할 것이다.

    이것은 내가 생각할 수있는 가장 간단한 가능한 해결책이지만, 중첩 된 if보다는 조기 복귀와 같은 몇 가지 개선을 할 것입니다.

    @Component
    public class SomeScheduledJob implements Job {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(SomeScheduledJob.class);
    
        @Value("${jobs.mediafiles.imagesPurgeJob.enable}")
        private boolean imagesPurgeJobEnable;
    
        @Override
        @Scheduled(cron = "${jobs.mediafiles.imagesPurgeJob.schedule}")
        public void execute() {
    
            if(!imagesPurgeJobEnable){
                return;
            }
            Do your conditional job here...
       }
    

    위 코드의 속성

    jobs.mediafiles.imagesPurgeJob.enable=true or false
    jobs.mediafiles.imagesPurgeJob.schedule=0 0 0/12 * * ?
    
  3. ==============================

    3.얼마 전 필자는 모든 구성 요소가 새로운 예약 된 작업을 만들거나 스케줄러 (모든 작업)를 중지 할 수 있어야한다는 것을 내 프로젝트에서 요구했습니다. 그래서 나는 이런 것을했다.

    얼마 전 필자는 모든 구성 요소가 새로운 예약 된 작업을 만들거나 스케줄러 (모든 작업)를 중지 할 수 있어야한다는 것을 내 프로젝트에서 요구했습니다. 그래서 나는 이런 것을했다.

    @Configuration
    @EnableScheduling
    @ComponentScan
    @Component
    public class CentralScheduler {
    
        private static AnnotationConfigApplicationContext CONTEXT = null;
    
        @Autowired
        private ThreadPoolTaskScheduler scheduler;
    
        public static CentralScheduler getInstance() {
            if (!isValidBean()) {
                CONTEXT = new AnnotationConfigApplicationContext(CentralScheduler.class);
            }
    
            return CONTEXT.getBean(CentralScheduler.class);
        }
    
        @Bean
        public ThreadPoolTaskScheduler taskScheduler() {
            return new ThreadPoolTaskScheduler();
        }
    
        public void start(Runnable task, String scheduleExpression) throws Exception {
            scheduler.schedule(task, new CronTrigger(scheduleExpression));
        }
    
        public void start(Runnable task, Long delay) throws Exception {
            scheduler.scheduleWithFixedDelay(task, delay);
        }
    
        public void stopAll() {
            scheduler.shutdown();
            CONTEXT.close();
        }
    
        private static boolean isValidBean() {
            if (CONTEXT == null || !CONTEXT.isActive()) {
                return false;
            }
    
            try {
                CONTEXT.getBean(CentralScheduler.class);
            } catch (NoSuchBeanDefinitionException ex) {
                return false;
            }
    
            return true;
        }
    }
    

    그래서 나는 같은 것을 할 수있다.

    Runnable task = new MyTask();
    CentralScheduler.getInstance().start(task, 30_000L);
    CentralScheduler.getInstance().stopAll();
    

    몇 가지 이유로 동시성에 대해 걱정할 필요없이이를 수행했음을 명심하십시오. 그렇지 않으면 약간의 동기화가 있어야합니다.

  4. ==============================

    4.다음은 예약 된 모든 실행중인 작업을 중지하고 시작하고 나열 할 수있는 예제입니다.

    다음은 예약 된 모든 실행중인 작업을 중지하고 시작하고 나열 할 수있는 예제입니다.

    @RestController
    @RequestMapping("/test")
    public class TestController {
    
    private static final String SCHEDULED_TASKS = "scheduledTasks";
    
    @Autowired
    private ScheduledAnnotationBeanPostProcessor postProcessor;
    
    @Autowired
    private ScheduledTasks scheduledTasks;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @GetMapping(value = "/stopScheduler")
    public String stopSchedule(){
        postProcessor.postProcessBeforeDestruction(scheduledTasks, SCHEDULED_TASKS);
        return "OK";
    }
    
    @GetMapping(value = "/startScheduler")
    public String startSchedule(){
        postProcessor.postProcessAfterInitialization(scheduledTasks, SCHEDULED_TASKS);
        return "OK";
    }
    
    @GetMapping(value = "/listScheduler")
    public String listSchedules() throws JsonProcessingException{
        Set<ScheduledTask> setTasks = postProcessor.getScheduledTasks();
        if(!setTasks.isEmpty()){
            return objectMapper.writeValueAsString(setTasks);
        }else{
            return "No running tasks !";
        }
    }
    

    }

  5. ==============================

    5.spring 프로세스가 Scheduled 일 때,이 주석으로 주석 처리 된 각 메소드를 반복하고 다음 소스가 보여주는 것처럼 Bean별로 태스크를 구성합니다.

    spring 프로세스가 Scheduled 일 때,이 주석으로 주석 처리 된 각 메소드를 반복하고 다음 소스가 보여주는 것처럼 Bean별로 태스크를 구성합니다.

    private final Map<Object, Set<ScheduledTask>> scheduledTasks =
            new IdentityHashMap<Object, Set<ScheduledTask>>(16);
    

    반복되는 예약 된 작업을 취소하려는 경우 다음과 같이 할 수 있습니다 (여기 내 repo에서 실행 가능한 데모).

    @Autowired
    private ScheduledAnnotationBeanPostProcessor postProcessor;
    @Autowired
    private TestSchedule testSchedule;
    
    public void later() {
        postProcessor.postProcessBeforeDestruction(test, "testSchedule");
    }
    

    이 Bean의 예약 된 작업을 찾아서 하나씩 취소합니다. 주목해야 할 점은 현재 실행중인 메소드 (postProcess Before Destruction 소스가 보여 주듯이)를 멈추게 할 것입니다.

        synchronized (this.scheduledTasks) {
            tasks = this.scheduledTasks.remove(bean); // remove from future running
        }
        if (tasks != null) {
            for (ScheduledTask task : tasks) {
                task.cancel(); // cancel current running method
            }
        }
    
  6. from https://stackoverflow.com/questions/44644141/how-to-stop-a-scheduled-task-that-was-started-using-scheduled-annotation by cc-by-sa and MIT license