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


78

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

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

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

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

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


다른 질문에서와 같이 유일한 표준 방법은 #주석 문자로 명령을 시작하는 것 입니다.
— Barmar

1
분명하지 않을 수도 있습니다. Spring / Quartz 프레임 워크가 cron 구문을 사용하지만 이것은 crontab이 아닙니다. cron은 XML 필드에서 사용됩니다 <property name="cronExpression" value="<expression>" /> . 줄에 주석을 달아 작업을 비활성화 할 수 없습니다. 그래도 고마워. 나는 그들이 사라질 것이라는 것을 알고있는 미래의 컴퓨터에서 지금까지 연도를 지정하는 제안 된 방법을 사용할 것입니다.
— Chop

분명히 Quartz cron 표현식은 Unix cron 표현식과는 다릅니다. Unix cron에는 몇 초 또는 몇 년이 없기 때문입니다. cron 태그는 아마도이 질문에 적합하지 않을 것입니다.
— Barmar

당신 말이 맞아요, 나는 이미 몇 가지 불일치를 만났습니다. 'cron'태그를 제거하겠습니다.
— Chop

답변:


73

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의 솔루션을 테스트하면서 나를 바보로 만들고 내 테스트가 내 테스트가 아니라는 것을 증명할 때 잊은 부분입니다.


3
왜 안돼 0 0 0 1 1 ? 1970? Quartz가 거절할까요?
— Arnaud Denoyelle

5
아르노의 제안 사용할 때 석영 2.1.0은 SchedulerException 던졌습니다 "구성 일정에 기반을 주어진 트리거는 것이다 결코 파일"과 시작은 내 Grails의 응용 프로그램에서 실패하지 않습니다
— hippofluff

2
답을 업데이트 해주셔서 감사합니다! +1 :) 참고로, 미래의 날짜에 허용되는 시간은 100 년입니다. 앞으로 100 년이 넘도록 예정된 것은 일정에 실패 할 것입니다. 왜 그들이 100 년을 안주했는지는 모르겠지만 응용 프로그램이 실제로 실행될만큼 충분히 오래 실행된다면 정말 감동을받을 것입니다. 이 기술은 심지어 100 년의 알려진 그럼에도 불구하고 경우
— hippofluff

2
나는 코드 [1]에서 1 년 동안의 마법 값을 확인했다 (2200은 나에게 실패) (javadoc [2]는 2199는 최대, 튜토리얼 [3]은 2099는 최대라고 말한다). 실제 최대 값은 다음과 같습니다. public static final int MAX_YEAR = Calendar.getInstance (). get (Calendar.YEAR) + 100; 따라서 올해 최대 값은 2116입니다. 내년 최대 값은 2117입니다. [1] fisheye.terracotta.org/browse/Quartz/trunk/quartz-core/src/main/… [2] quartz-scheduler.org/api/2.2. 1 / 조직 / 수정 / CronExpression.html [3] quartz-scheduler.org/documentation/quartz-2.x/tutorials/...
— DelGurth

1
@Chop 예, 사용하기 쉽기 때문에 감사합니다. 테라코타에서 문서화 버그를 제기했습니다. 현재는 혼란 스럽기 때문에 실제 코드에서도 다른 최대 연도 검사를 사용합니다.
— DelGurth

42

기술적으로 선택적 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 ?

나는 실제로 Quartz가 내가 그에게 준 크론을 받아들이도록 연도를 줄였습니다. 귀하의 솔루션은 실제로 매우 우아합니다. 감사!
— Chop

9
흠, 마침내이 제안을 테스트 할 기회를 얻었습니다. Quartz가이 크론이 절대 실행되지 않는다는 것을 감지했기 때문에 거부하는 것 같습니다 ...
— Chop

동일한 방법이 Rails에서 잘 작동하는 것처럼 보였기 때문에 한 번의 기회였습니다. 을 사용 .startAt(startTime)하여 트리거가 오래 전에 시작되었다고 생각하도록 한 다음 이미 지난 특정 연도에만 실행하도록 지시 할 수 있습니다. 그러나 이것은 그다지 우아하지 않습니다.
— Eric Tjossem 2013 년

1
0 5 31 2 *하나는 젠토의 크론에서 잘 작동하는 것 같다.
— toon81

3
이 오류 작동하지 않습니다Invalid cron expression "0 0 5 31 2 ?" led to runaway search for next trigger
— 프랭키 드레이크에게

25

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


대신 그것을 사용하는 것이이기는 것이 무엇인지 설명해 주 0 0 0 1 1 ? 2200시겠습니까? 내 것은 2200 Ney Year 's Eve에 촉발 될 것이고, 당신은 내가 이해하는 바와 같이 100 년 전에 만 촉발 될 것입니다. 내가 잘못 했나? 그렇지 않다면 앞으로 더 멀어 질수록 더 좋다고 생각하지 않습니까?
— Chop

11
석영은 적어도 석영 1.6 봄 2.5.6SEC3 작업을 시작하기를 거부 너의이 마지막 유효 석영 표현
— 마치에이 Matys

나는 문서를 보았고 당신이 맞습니다. 이것은 마지막 유효한 표현입니다. 그래도 0 0 0 1 1 ? 2200최신 버전의 Quartz 에서 작동합니다. 그러나 더 똑똑한 솔루션이 제안되었습니다 (내 답변의 편집 참조).
— Chop

7

비슷한 문제 (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시에만 실행됩니다.


이것은 내가 가장 좋아하는 해결 방법입니다! 배지
— 가치

6

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

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

2

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

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

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

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


1

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

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

schedular.cron.expression=-
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.