[spring] Quartz : 절대 실행되지 않는 Cron 표현식

나는 여기 에 중복이 있다는 것을 알고 있는데 , 아마도 정확히 나의 경우 일 것이다. 비록 더 나은 설명이 필요하지만 여기에서 제공하려고 노력할 것이다.

Spring 애플리케이션 컨텍스트를 사용하여 Java 웹 애플리케이션으로 작업합니다. 이 맥락에서 저는 Quartz를 사용하여 예정된 작업을 정의했습니다. 이러한 작업은 .properties 파일에 정의 된 cron에 의해 트리거됩니다.

Spring 컨텍스트는 war 내에 임베드되는 반면 .properties 파일은 애플리케이션 서버 (이 특정 경우에는 Tomcat)에 있습니다.

이것은 괜찮으며 환경 (개발, 통합, 생산 등)에 따라 다른 크론을 정의 할 수 있습니다.

이제이 응용 프로그램을 내 컴퓨터에서 로컬로 실행할 때 이러한 작업이 실행되는 것을 원하지 않습니다. 트리거하지 않는 cron 표현식을 작성하는 방법이 있습니까?



답변

TL; DR

Quartz 1에서는 다음 cron : 59 59 23 31 12 ? 2099(마지막 유효 날짜)를 사용할 수 있습니다 .
Quartz 2에서는 다음 크론을 사용할 수 있습니다.0 0 0 1 1 ? 2200

먼 미래의 표현 사용

.NET을 사용하여 몇 가지 빠른 테스트를 수행했습니다 org.quartz.CronExpression.

String exp = "0 0 0 1 1 ? 3000";
boolean valid = CronExpression.isValidExpression(exp);
System.out.println(valid);
if (valid) {
    CronExpression cronExpression = new CronExpression(exp);
    System.out.println(cronExpression.getNextValidTimeAfter(new Date()));
}

그렇게 String exp = "# 0 0 0 1 1 ?";하면 isValid테스트가 반환 false됩니다.

위에 제공된 샘플을 사용하면 출력은 다음과 같습니다.

true
null

의미:

  • 표현식이 유효합니다.
  • 이 표현과 일치하는 예정된 날짜가 없습니다.

하지만 스케줄러가 cron 트리거를 수락하려면 후자 미래의 날짜와 일치 해야합니다 .

나는 몇 년을 시도하고 일년이 2300을 넘으면 Quartz가 더 이상 귀찮게 보이지 않는다는 것을 알아 냈습니다 ( Quartz 2의 문서에서 올해 최대 값에 대한 언급을 찾지 못했지만 ). 이 작업을 수행하는 더 깨끗한 방법이있을 수 있지만 지금은 내 요구를 충족시킬 것입니다.

그래서 결국 내가 제안하는 cron은 0 0 0 1 1 ? 2200.

Quartz 1 변형

Quartz 1에서 2099 년은 마지막 유효 연도 입니다. 따라서 Maciej Matys의 제안 을 사용하도록 cron 표현식을 조정할 수 있습니다 .59 59 23 31 12 ? 2099

대안 : 과거 날짜 사용

Arnaud Denoyelle 은 더 우아한 것을 제안했는데, 위의 테스트에서 올바른 표현으로 검증했습니다. 먼 미래의 날짜를 선택하는 대신 먼 과거의 날짜를 선택하십시오.

0 0 0 1 1 ? 1970 (Quartz 문서에 따른 첫 번째 유효한 표현식).

이 솔루션은 작동하지 않습니다.

hippofluff 는 Quartz가 과거에 표현식을 감지 할 것이므로 다시는 실행되지 않으므로 예외가 발생 한다고 강조했습니다.

org.quartz.SchedulerException: Based on configured schedule, the given trigger will never fire.

이것은 오랫동안 Quartz 있었던 것 같다 .

배운 교훈 : 테스트는 그대로 완벽하지 않습니다.

이것은 내 테스트의 약점을 강조합니다. a를 테스트 하려면 1 이 있어야한다는CronExpression 것을 기억 하십시오nextValidTime . 그렇지 않으면 전달할 스케줄러가 위에서 언급 한 예외와 함께이를 거부합니다.

다음과 같이 테스트 코드를 수정하는 것이 좋습니다.

String exp = "0 0 0 1 1 ? 3000";
boolean valid = CronExpression.isValidExpression(exp);
if (valid) {
    CronExpression cronExpression = new CronExpression(exp);
    valid = cronExpression.getNextValidTimeAfter(new Date()) != null;
}
System.out.println("Can I use <" + exp + ">? " + (valid ? "Go ahead!" : "This shall fail."));

이제 생각할 필요없이 출력을 읽으십시오.


1 이것은 Arnaud의 솔루션을 테스트하면서 나를 바보로 만들고 내 테스트가 내 테스트가 아니라는 것을 증명할 때 잊은 부분입니다.


답변

기술적으로 선택적 Quartz 연도 필드의 유효한 값은 1970-2099이므로 2300은 예상 값이 아닙니다. 나는 당신이 정말로 이것을 할 필요가 있고 Quartz 버전이 유효한 cron 구문을 시행하려고 시도 한다고 가정하고 있습니다 (1 ~ 31 일, 1 ~ 12 월 등).

저는 현재 Resque-scheduler for Rails에서 다음 코드를 사용하고 있습니다. Resque-scheduler for Rails는 확인 된 crontab 형식의 일정 정보를 받아 수동 실행 전용 테스트 작업을 생성합니다.

cron: "0 5 31 2 *"

작업은 실행되기 전에 2 월 31 일 이른 아침을 참을성있게 기다립니다 . Quartz crontrigger에 해당하는 내용을 보려면 다음 줄 또는 일부 변형을 시도하십시오.

0 0 5 31 2 ?


답변

이것을 시도하십시오 : 59 59 23 31 12 ? 2099


답변

비슷한 문제 (cron 표현식 비활성화)를 해결하려고 시도하는 동안 이것을 발견했지만 유효한 미래 일정 날짜를 요구하는 것과 동일한 문제가 발생했습니다.

또한 7 값 구문을 사용하여 문제가 발생했습니다. cron 일정에 연도를 지정할 수 없습니다.

그래서 이것을 사용했습니다 : 0 0 3? 2 월 5 일

다음에 실행될 시간은 다음과 같습니다.

  1. 2044 년 2 월 29 일 월요일 오전 3:00
  2. 2072 년 2 월 29 일 월요일 오전 3:00
  3. 2112 년 2 월 29 일 월요일 오전 3:00
  4. 2140 년 2 월 29 일 월요일 오전 3:00
  5. 2168 년 2 월 29 일 월요일 오전 3:00

따라서 본질적으로 모든 의도와 목적에 따라 비활성화됩니다. 🙂

아. 저주, 이것은 Quartz 스케줄러 구문에서만 작동합니다-Spring CronTrigger 구문은 다섯 번째 월요일에 MON # 5를 허용하지 않습니다.

그래서 차선책은 0 0 3 29 2? 2 월 29 일 (윤년) 오전 3시에만 실행됩니다.


답변

표현식에서 표현식을 사용하는 경우 @Scheduled(cron="")(기술적으로 쿼츠를 사용하지 않고 봄에 일반적으로 사용하는 경우) 7 필드 연중 솔루션을 사용할 수 없지만 다음 옵션을 사용할 수 있습니다.

  • Spring 5.1+ (springBoot 2.1+)를 사용하는 경우 "${your.cron.prop:-}실행을 비활성화하도록 속성을 설정하지 않고 사용 하기 만하면 됩니다. @Scheduled를 참조하십시오 . 또는 속성 자체를 “-“로 설정합니다 (yml을 사용하는 경우 따옴표를 사용해야 함).
  • @Scheduled예를 들어, @ConditionalOnProperty("my.scheduleproperty.active")어노테이션 을 사용 하고 특성을 설정하지 않고 (또는로 설정 false) 메소드로 Bean / 서비스를 모두 비활성화하십시오.


답변

이제이 응용 프로그램을 내 컴퓨터에서 로컬로 실행할 때 이러한 작업이 실행되는 것을 원하지 않습니다. 트리거하지 않는 cron 표현식을 작성하는 방법이 있습니까?

컴퓨터에서 예약을 비활성화하려면 여러 가지 방법으로 수행 할 수 있습니다.

먼저 Quartz 구성을 @Profile기반 구성으로 이동 하고이 프로파일을 로컬로 활성화하지 않을 수 있습니다. 프로필이 활성화되지 않으면 Quartz가 전혀 시작되지 않습니다.

대안은 Quartz가 자동으로 시작되지 않도록 구성하는 것입니다. 개발자 프로필 SchedulerFactoryBean#setAutoStartup()BeanPostProcessor등록하여 설정할 수 있는 것이 있습니다 . 이 스레드는 꽤 오래되었지만 Spring Boot는 SchedulerFactoryBeanCustomizer동일한 작업을 수행하기 위해 Bean을 등록하여 대안을 제공합니다 .


답변

안녕하세요 당신은 단지로 전달할 그것은 당신의 schedular을 실행하지 않습니다이 시도 할 수 있습니다 -크론에서

 @Scheduled(cron = "${schedular.cron.expression}")

schedular.cron.expression=-