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.