복붙노트

[SPRING] Spring Boot IntegrationTest에서 @Schedule 비활성화

SPRING

Spring Boot IntegrationTest에서 @Schedule 비활성화

Spring Boot IntegrationTest에서 스케줄 자동 시작을 비활성화하려면 어떻게합니까?

감사.

해결법

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

    1.외부 컴포넌트가 자동으로 스케줄링을 가능하게 할 수 있음에 유의하십시오 (Spring Framework에서 HystrixStreamAutoConfiguration 및 MetricExportAutoConfiguration 참조). 따라서 @EnableScheduling을 지정하는 @Configuration 클래스에서 @ConditionalOnProperty 또는 @Profile을 사용하려고하면 외부 구성 요소로 인해 일정이 활성화됩니다.

    외부 컴포넌트가 자동으로 스케줄링을 가능하게 할 수 있음에 유의하십시오 (Spring Framework에서 HystrixStreamAutoConfiguration 및 MetricExportAutoConfiguration 참조). 따라서 @EnableScheduling을 지정하는 @Configuration 클래스에서 @ConditionalOnProperty 또는 @Profile을 사용하려고하면 외부 구성 요소로 인해 일정이 활성화됩니다.

    @EnableScheduling을 통해 예약 할 수있는 하나의 @Configuration 클래스가 있지만 각각 @ConditionalOnProperty를 사용하여 @Scheduled 작업이 포함 된 클래스를 활성화 / 비활성화하는 별도의 클래스로 예약 된 작업을 갖습니다.

    동일한 클래스에 @Scheduled 및 @EnableScheduling이 없거나 외부 구성 요소가이를 활성화하는 문제가 발생하므로 @ConditionalOnProperty가 무시됩니다.

    예 :

    @Configuration
    @EnableScheduling
    public class MyApplicationSchedulingConfiguration {
    }
    

    그리고 별도의 수업에서

    @Named
    @ConditionalOnProperty(value = "scheduling.enabled", havingValue = "true", matchIfMissing = false)
    public class MyApplicationScheduledTasks {
    
      @Scheduled(fixedRate = 60 * 60 * 1000)
      public void runSomeTaskHourly() {
        doStuff();
      }
    }
    

    이 솔루션의 문제점은 모든 예약 된 작업이 @ConditionalOnProperty가 지정된 자체 클래스에 있어야한다는 것입니다. 해당 주석을 놓치면 작업이 실행됩니다.

    ThreadPoolTaskScheduler를 확장하고 TaskScheduler 메소드를 대체하십시오. 이 방법에서는 작업을 실행해야하는지 확인하기 위해 점검을 수행 할 수 있습니다.

    그런 다음 @EnableScheduling을 사용하는 @Configuration 클래스에서 사용자 정의 스레드 풀 작업 스케줄러를 반환하는 taskScheduler라는 @Bean을 만듭니다.

    예 :

    public class ConditionalThreadPoolTaskScheduler extends ThreadPoolTaskScheduler {
    
      @Inject
      private Environment environment;
    
      // Override the TaskScheduler methods
      @Override
      public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
        if (!canRun()) {
          return null;
        }
        return super.schedule(task, trigger);
      }
    
      @Override
      public ScheduledFuture<?> schedule(Runnable task, Date startTime) {
        if (!canRun()) {
          return null;
        }
        return super.schedule(task, startTime);
      }
    
      @Override
      public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
        if (!canRun()) {
          return null;
        }
        return super.scheduleAtFixedRate(task, startTime, period);
      }
    
      @Override
      public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
        if (!canRun()) {
          return null;
        }
        return super.scheduleAtFixedRate(task, period);
      }
    
      @Override
      public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
        if (!canRun()) {
          return null;
        }
        return super.scheduleWithFixedDelay(task, startTime, delay);
      }
    
      @Override
      public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay) {
        if (!canRun()) {
          return null;
        }
        return super.scheduleWithFixedDelay(task, delay);
      }
    
      private boolean canRun() {
        if (environment == null) {
          return false;
        }
    
        if (!Boolean.valueOf(environment.getProperty("scheduling.enabled"))) {
          return false;
        }
    
        return true;
      }
    }
    

    사용자 정의 스케줄러를 사용하여 taskScheduler Bean을 작성하고 스케줄링을 가능하게하는 구성 클래스

    @Configuration
    @EnableScheduling
    public class MyApplicationSchedulingConfiguration {
    
      @Bean
      public TaskScheduler taskScheduler() {
        return new ConditionalThreadPoolTaskScheduler();
      }
    }
    

    위의 잠재적 인 문제는 내부 Spring 클래스에 대한 종속성을 만들었으므로 향후 변경 사항이 있으면 호환성을 수정해야한다는 것입니다.

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

    2.나는 같은 문제가 있었다. 내 Scheduling Bean을 사용한 Spring의 @ConditionalOnProperty 속성을 시도했지만 스케줄링은 여전히 ​​테스트에서 활성화되었습니다.

    나는 같은 문제가 있었다. 내 Scheduling Bean을 사용한 Spring의 @ConditionalOnProperty 속성을 시도했지만 스케줄링은 여전히 ​​테스트에서 활성화되었습니다.

    내가 찾은 유일한 좋은 해결 방법은 테스트 클래스의 일정 속성을 덮어 써서 작업을 실제로 실행할 기회가 없도록하는 것입니다.

    실제 작업이 my.cron = 0 0/5 * * * * 속성을 사용하여 5 분마다 실행되는 경우

    public class MyJob {
    
        @Scheduled(cron = "${my.cron}")
        public void execute() {
            // do something
        }
    } 
    

    그런 다음 테스트 클래스에서 다음과 같이 구성 할 수 있습니다.

    @RunWith(SpringRunner.class)
    @SpringBootTest(properties = {"my.cron=0 0 0 29 2 ?"}) // Configured as 29 Feb ;-)
    public class MyApplicationTests {
    
        @Test
        public void contextLoads() {
        }
    
    }
    

    따라서 작업이 활성화 되더라도 4 년에 한 번 발생하는 2 월 29 일 0 일에만 실행됩니다. 그래서 당신은 그것을 실행할 가능성이 매우 적습니다.

    요구 사항에 맞게 더 멋진 cron 설정을 만들 수 있습니다.

  3. ==============================

    3.한 가지 방법은 스프링 프로파일을 사용하는 것입니다

    한 가지 방법은 스프링 프로파일을 사용하는 것입니다

    시험 수업에서 :

    @SpringBootTest(classes = Application.class)
    @ActiveProfiles("integration-test")
    public class SpringBootTestBase {
        ...
    }
    

    스케줄러 클래스 또는 메소드에서 :

    @Configuration
    @Profile("!integration-test") //to disable all from this configuration
    public class SchedulerConfiguration {
    
        @Scheduled(cron = "${some.cron}")
        @Profile("!integration-test") //to disable a specific scheduler
        public void scheduler1() {
            // do something
        }
    
        @Scheduled(cron = "${some.cron}")
        public void scheduler2() {
            // do something
        }
    
        ...
    }
    
  4. ==============================

    4.실제 Spring Boot Application 클래스가 다음과 같은 경우 :

    실제 Spring Boot Application 클래스가 다음과 같은 경우 :

    @SpringBootApplication   
    @EnableScheduling
    public class MyApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MyApplication.class, args);
        }
    
    }
    

    다음과 같이 통합 테스트를 위해 @EnableScheduling없이 다른 Application 클래스를 작성해야합니다.

    @SpringBootApplication   
    public class MyTestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MyTestApplication.class, args);
        }
    
    }
    

    그런 다음 통합 테스트에서 MyTestApplication 클래스를 다음과 같이 사용하십시오.

    RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = MyTestApplication.class)
    public class MyIntegrationTest {
    
    ...
    }
    

    내가 더 좋은 방법을 찾지 못했기 때문에 그것이 내가하는 방식입니다.

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

    5.Spring Boot 2.0.3에서 알아 낸 쉬운 솔루션 :

    Spring Boot 2.0.3에서 알아 낸 쉬운 솔루션 :

    1) 예약 된 메소드를 별도의 Bean으로 추출

    @Service
    public class SchedulerService {
    
      @Autowired
      private SomeTaskService someTaskService;
    
      @Scheduled(fixedRate = 60 * 60 * 1000)
      public void runSomeTaskHourly() {
        someTaskService.runTask();
      }
    }
    

    2) 테스트 클래스에서 스케줄러 Bean을 조롱하십시오.

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SomeTaskServiceIT {
    
      @Autowired
      private SomeTaskService someTaskService;
    
      @MockBean
      private SchedulerService schedulerService;
    }
    
  6. ==============================

    6.별도의 구성 클래스를 사용하여이 문제를 해결 한 다음 테스트 컨텍스트에서이 클래스를 덮어 씁니다. 따라서 응용 프로그램에 주석을 넣는 대신 별도의 구성 클래스에만 주석을 넣었습니다. 일반적인 상황 :

    별도의 구성 클래스를 사용하여이 문제를 해결 한 다음 테스트 컨텍스트에서이 클래스를 덮어 씁니다. 따라서 응용 프로그램에 주석을 넣는 대신 별도의 구성 클래스에만 주석을 넣었습니다. 일반적인 상황 :

    @Configuration
    @EnableScheduling 
    public class SpringConfiguration {}
    

    테스트 컨텍스트 :

    @Configuration
    public class SpringConfiguration {}
    
  7. ==============================

    7.위의 답변을 통합하십시오.

    위의 답변을 통합하십시오.

    또한 항상 확인 :

    다음을 읽으십시오 :

  8. from https://stackoverflow.com/questions/40684903/disable-schedule-on-spring-boot-integrationtest by cc-by-sa and MIT license