Quartz보다 간단한 클러스터형 java.util.concurrent.ScheduledExecutorService
에 대한 필요성에서 영감을 받은 Java용 작업 스케줄러입니다.
따라서 사용자(cbarbosa2, rafaelhofmann, BukhariH)도 높이 평가합니다.
당신의 lib가 흔들립니다! Quartz를 없애고 다루기가 훨씬 더 쉬운 귀하의 것으로 교체하게 되어 정말 기쁩니다!
cbarbosa2
왜 Quartz가 아닌가?
< dependency >
< groupId >com.github.kagkarlsson</ groupId >
< artifactId >db-scheduler</ artifactId >
< version >15.0.0</ version >
</ dependency >
데이터베이스 스키마에 scheduled_tasks
테이블을 생성합니다. postgresql, oracle, mssql 또는 mysql에 대한 테이블 정의를 참조하세요.
스케줄러를 인스턴스화하고 시작하면 정의된 반복 작업이 시작됩니다.
RecurringTask < Void > hourlyTask = Tasks . recurring ( "my-hourly-task" , FixedDelay . ofHours ( 1 ))
. execute (( inst , ctx ) -> {
System . out . println ( "Executed!" );
});
final Scheduler scheduler = Scheduler
. create ( dataSource )
. startTasks ( hourlyTask )
. threads ( 5 )
. build ();
// hourlyTask is automatically scheduled on startup if not already started (i.e. exists in the db)
scheduler . start ();
더 많은 예를 보려면 계속 읽으세요. 내부 작동에 대한 자세한 내용은 작동 방식을 참조하세요. Spring Boot 애플리케이션이 있는 경우 Spring Boot Usage를 살펴보세요.
프로덕션에서 db-scheduler를 실행하는 것으로 알려진 조직 목록:
회사 | 설명 |
---|---|
디지포스트 | 노르웨이의 디지털 사서함 제공업체 |
Vy 그룹 | 북유럽 국가에서 가장 큰 운송 그룹 중 하나입니다. |
지혜로운 | 해외로 돈을 보내는 저렴하고 빠른 방법. |
베커 전문 교육 | |
모니터리아 | 웹사이트 모니터링 서비스. |
로드스터 | 웹 애플리케이션에 대한 부하 테스트. |
스테이튼스 베그베슨 | 노르웨이 공공 도로 관리청 |
광년 | 전 세계적으로 돈을 투자하는 간단하고 접근하기 쉬운 방법입니다. |
탐색 | 노르웨이 노동복지청 |
모던루프 | ModernLoop를 사용하여 인터뷰 일정, 커뮤니케이션 및 조정의 효율성을 높여 회사의 채용 요구 사항에 맞게 확장하세요. |
디피아 | 노르웨이 eHealth 회사 |
백조 | Swan은 개발자가 뱅킹 서비스를 제품에 쉽게 포함할 수 있도록 도와줍니다. |
톰라 | TOMRA는 재활용을 위한 역자동 판매기를 설계 및 제조하는 노르웨이의 다국적 기업입니다. |
자유롭게 PR을 열어 귀하의 조직을 목록에 추가하세요.
실행 가능한 예제도 참조하세요.
반복 작업을 정의하고 startTasks
빌더 메서드를 사용하여 시작 시 작업의 첫 번째 실행을 예약합니다. 완료되면 정의된 일정에 따라 작업 일정이 다시 조정됩니다(사전 정의된 일정 유형 참조).
RecurringTask < Void > hourlyTask = Tasks . recurring ( "my-hourly-task" , FixedDelay . ofHours ( 1 ))
. execute (( inst , ctx ) -> {
System . out . println ( "Executed!" );
});
final Scheduler scheduler = Scheduler
. create ( dataSource )
. startTasks ( hourlyTask )
. registerShutdownHook ()
. build ();
// hourlyTask is automatically scheduled on startup if not already started (i.e. exists in the db)
scheduler . start ();
여러 인스턴스 및 일정이 포함된 반복 작업의 경우 RecurringTaskWithPertantScheduleMain.java 예제를 참조하세요.
일회성 작업의 인스턴스는 미래의 특정 시점(즉, 반복되지 않음)에 단일 실행 시간을 갖습니다. 인스턴스 ID는 이 작업 내에서 고유해야 하며 일부 메타데이터(예: ID)를 인코딩하는 데 사용될 수 있습니다. 더 복잡한 상태의 경우 사용자 정의 직렬화 가능 Java 객체가 지원됩니다(예제에서 사용됨).
일회성 작업을 정의하고 스케줄러를 시작합니다.
TaskDescriptor < MyTaskData > MY_TASK =
TaskDescriptor . of ( "my-onetime-task" , MyTaskData . class );
OneTimeTask < MyTaskData > myTaskImplementation =
Tasks . oneTime ( MY_TASK )
. execute (( inst , ctx ) -> {
System . out . println ( "Executed! Custom data, Id: " + inst . getData (). id );
});
final Scheduler scheduler = Scheduler
. create ( dataSource , myTaskImplementation )
. registerShutdownHook ()
. build ();
scheduler . start ();
... 그리고 어느 시점(런타임)에 SchedulerClient
를 사용하여 실행이 예약됩니다.
// Schedule the task for execution a certain time in the future and optionally provide custom data for the execution
scheduler . schedule (
MY_TASK
. instanceWithId ( "1045" )
. data ( new MyTaskData ( 1001L ))
. scheduledTo ( Instant . now (). plusSeconds ( 5 )));
예 | 설명 |
---|---|
EnableImmediateExecutionMain.java | now() 또는 그 이전에 실행되도록 실행을 예약하면 로컬 Scheduler 이에 대한 힌트가 표시되고 "깨어나서" 평소보다 일찍 새 실행을 확인합니다( pollingInterval 에 의해 구성됨). |
MaxRetriesMain.java | 실행 시 재시도 횟수에 대한 제한을 설정하는 방법입니다. |
ExponentialBackoffMain.java | 기본값인 고정 지연 대신 지수 백오프를 재시도 전략으로 사용하는 방법입니다. |
ExponentialBackoffWithMaxRetriesMain.java | 지수 백오프를 재시도 전략으로 사용 하고 최대 재시도 횟수에 대한 엄격한 제한을 사용하는 방법입니다. |
TrackingProgressRecurringTaskMain.java | 반복 작업은 실행 전반에 걸쳐 상태를 유지하는 방법으로 task_data 저장할 수 있습니다. 이 예에서는 방법을 보여줍니다. |
SpawningOtherTasksMain.java | executionContext.getSchedulerClient() 사용하여 다른 인스턴스의 작업 예약 인스턴스를 보여줍니다. |
SchedulerClientMain.java | SchedulerClient 의 기능 중 일부를 보여줍니다. 예약, 예약된 실행 가져오기 등 |
RecurringTaskWithPertantScheduleMain.java | Schedule task_data 의 일부로 저장되는 다중 인스턴스 반복 작업입니다. 예를 들어 각 테넌트에 반복 작업이 있어야 하는 다중 테넌트 애플리케이션에 적합합니다. |
StatefulRecurringTaskWithPertantScheduleMain.java | |
JsonSerializerMain.java | task_data 의 직렬화를 Java 직렬화(기본값)에서 JSON으로 재정의합니다. |
JobChainingTaskDataMain.java 사용 | 작업 체인, 즉 "이 인스턴스 실행이 완료되면 다른 작업을 예약합니다. |
JobChainingUsingSeparateTasksMain.java | 위와 같이 Job Chaining이 가능합니다. |
인터셉터Main.java | ExecutionInterceptor 사용하여 모든 ExecutionHandler 에 대한 실행 전후에 로직을 주입합니다. |
예 | 설명 |
---|---|
기본예제 | 기본적인 일회성 작업과 반복 작업 |
트랜잭션 단계적 작업 | 트랜잭션을 통해 작업을 준비하는 예, 즉 트랜잭션이 커밋 되면 백그라운드 작업이 실행되는지 확인합니다(다른 db 수정과 함께). |
장기 실행 작업 | 장기 실행 작업은 애플리케이션을 다시 시작해도 유지 되고 처음부터 다시 시작되지 않아야 합니다. 이 예에서는 종료 시 진행 상황을 유지하는 방법과 야간에 실행되도록 작업을 제한하는 기술을 보여줍니다. |
반복 상태 추적 | 각 실행 후 수정될 수 있는 상태를 포함하는 반복 작업입니다. |
병렬JobSpawner | 병렬화 등을 위해 반복 작업을 사용하여 일회성 작업을 생성하는 방법을 보여줍니다. |
JobChaining | 여러 단계가 포함된 일회성 작업입니다. 다음 단계는 이전 단계가 완료된 후에 예약됩니다. |
멀티인스턴스반복 | 유형은 동일하지만 일정과 데이터가 다를 수 있는 여러 반복 작업을 수행하는 방법을 보여줍니다. |
스케줄러는 Scheduler.create(...)
빌더를 사용하여 생성됩니다. 빌더에는 적절한 기본값이 있지만 다음 옵션을 구성할 수 있습니다.
.threads(int)
스레드 수. 기본값 10
.
.pollingInterval(Duration)
스케줄러가 데이터베이스에서 적절한 실행을 확인하는 빈도입니다. 기본값은 10s
입니다.
.alwaysPersistTimestampInUTC()
Scheduler는 지속되는 타임스탬프에 대한 열이 LocalDateTime
이 아닌 Instant
를 유지한다고 가정합니다. 즉, 어떻게든 타임스탬프를 영역에 연결합니다. 그러나 일부 데이터베이스는 이러한 유형(영역 정보가 없음)이나 기타 특이한 사항에 대한 지원이 제한되어 있으므로 "항상 UTC로 저장"하는 것이 더 나은 대안입니다. 이러한 경우 이 설정을 사용하여 인스턴트를 항상 UTC로 저장하세요. PostgreSQL 및 Oracle 스키마는 영역 정보를 보존하기 위해 테스트되었습니다. MySQL 및 MariaDB 스키마는 이 설정을 사용 하지 않으며 사용해야 합니다. 주의: 이전 버전과의 호환성을 위해 "알 수 없는" 데이터베이스의 기본 동작은 데이터베이스가 시간대를 유지한다고 가정하는 것입니다. "알려진" 데이터베이스의 경우 AutodetectJdbcCustomization
클래스를 참조하세요.
.enableImmediateExecution()
이것이 활성화되면 스케줄러는 now()
또는 과거 시간에 실행되도록 예약된 후에 실행될 실행이 있음을 로컬 Scheduler
에 암시하려고 시도합니다. 주의: schedule(..)
/ reschedule(..)
에 대한 호출이 트랜잭션 내에서 발생하는 경우 스케줄러는 업데이트가 표시되기 전에 실행을 시도할 수 있습니다(트랜잭션이 커밋되지 않음). 그래도 여전히 지속되므로 누락되더라도 다음 polling-interval
이전에 실행됩니다. 스케줄러 메서드 scheduler.triggerCheckForDueExecutions()
)를 사용하여 예정된 실행에 대한 조기 확인을 프로그래밍 방식으로 트리거할 수도 있습니다. 기본값은 false
.
.registerShutdownHook()
종료 시 Scheduler.stop()
호출하는 종료 후크를 등록합니다. 정상적인 종료와 중단된 실행을 방지하려면 항상 중지를 호출해야 합니다.
.shutdownMaxWait(Duration)
실행기 서비스 스레드를 중단하기 전에 스케줄러가 대기하는 시간입니다. 이 기능을 사용하고 있다면 ExecutionHandler에서 executionContext.getSchedulerState().isShuttingDown()
정기적으로 확인하고 장기 실행 작업을 중단하는 것이 가능한지 고려해보세요. 기본값은 30min
입니다.
.enablePriority()
데이터베이스에서 예정된 실행을 가져오는 순서를 결정하는 실행 우선순위를 정의할 수 있습니다. 우선 순위 값이 더 높은 실행은 더 낮은 값을 가진 실행보다 먼저 실행됩니다(기술적으로 순서는 order by priority desc, execution_time asc
됩니다). 필드가 SMALLINT
로 정의되었으므로 0-32000 범위의 우선순위를 사용하는 것이 좋습니다. 더 큰 값이 필요한 경우 스키마를 수정하세요. 현재 이 기능은 선택되어 있으며 열 우선 priority
이 구성 설정을 통해 우선순위를 활성화하도록 선택한 사용자에게만 필요합니다.
TaskInstance.Builder
를 사용하여 인스턴스별 우선순위를 설정합니다.
scheduler . schedule (
MY_TASK
. instance ( "1" )
. priority ( 100 )
. scheduledTo ( Instant . now ()));
메모:
(execution_time asc, priority desc)
에 인덱스를 추가하는 것이 도움이 될 수 있습니다(이전 execution_time asc
교체).null
값은 데이터베이스(낮음 또는 높음)에 따라 다르게 해석될 수 있습니다. 초당 1000회 이상의 실행을 실행하는 경우 오버헤드를 낮추고 처리량을 높이기 위해 lock-and-fetch
폴링 전략을 사용할 수 있습니다(자세히 보기). 그렇지 않은 경우 기본 fetch-and-lock-on-execute
문제가 없습니다.
.pollUsingFetchAndLockOnExecute(double, double)
기본 폴링 전략인 fetch-and-lock-on-execute
를 사용합니다.
데이터베이스의 마지막 가져오기가 전체 배치( executionsPerBatchFractionOfThreads
)인 경우 남은 실행 수가 lowerLimitFractionOfThreads * nr-of-threads
이하일 때 새 가져오기가 트리거됩니다. 가져온 실행은 잠기거나 선택되지 않으므로 스케줄러는 실행될 때 잠금을 위해 다른 인스턴스와 경쟁합니다. 모든 데이터베이스에서 지원됩니다.
기본값: 0,5, 3.0
.pollUsingLockAndFetch(double, double)
업데이트를 위해 선택을 사용하는 폴링 전략 lock-and-fetch
사용합니다 select for update .. skip locked
뛰기를 사용합니다.
데이터베이스에서 마지막 가져오기가 전체 배치인 경우 남은 실행 수가 lowerLimitFractionOfThreads * nr-of-threads
이하일 때 새 가져오기가 트리거됩니다. 매번 가져오는 실행 수는 (upperLimitFractionOfThreads * nr-of-threads) - nr-executions-left
와 같습니다. 가져온 실행은 이 스케줄러 인스턴스에 대해 이미 잠겨/선택되어 있으므로 UPDATE
문 하나가 저장됩니다.
일반적인 사용의 경우 예를 들어 0.5, 1.0
으로 설정합니다.
높은 처리량(예: 스레드를 사용 중으로 유지)의 경우 예를 들어 1.0, 4.0
으로 설정합니다. 현재 대기열에서 선택된 실행에 대해 하트비트가 업데이트되지 않습니다( upperLimitFractionOfThreads > 1.0
인 경우 적용 가능). 실행을 시작하지 않고 4 * heartbeat-interval
(기본값 20m
) 이상 그곳에 머무르면 죽은 것으로 감지되어 다시 잠금이 해제될 가능성이 높습니다( DeadExecutionHandler
에 의해 결정됨). 현재 postgres 에서 지원됩니다. sql-server 도 이를 지원하지만 테스트 결과 교착 상태가 발생하기 쉬우므로 이해/해결될 때까지 권장되지 않습니다.
.heartbeatInterval(Duration)
실행 실행을 위해 하트비트 타임스탬프를 업데이트하는 빈도입니다. 기본 5m
.
.missedHeartbeatsLimit(int)
실행이 중단된 것으로 간주되기 전에 놓칠 수 있는 하트비트 수입니다. 기본값 6
.
.addExecutionInterceptor(ExecutionInterceptor)
실행에 대한 논리를 주입할 수 있는 ExecutionInterceptor
추가합니다. Spring Boot의 경우 간단히 ExecutionInterceptor
유형의 Bean을 등록하세요.
.addSchedulerListener(SchedulerListener)
스케줄러 및 실행 관련 이벤트를 수신할 SchedulerListener
를 추가합니다. Spring Boot의 경우 SchedulerListener
유형의 Bean을 등록하기만 하면 됩니다.
.schedulerName(SchedulerName)
이 스케줄러 인스턴스의 이름입니다. 스케줄러가 실행을 선택할 때 이름은 데이터베이스에 저장됩니다. 기본값 <hostname>
.
.tableName(String)
작업 실행을 추적하는 데 사용되는 테이블의 이름입니다. 테이블을 생성할 때 그에 따라 테이블 정의의 이름을 변경합니다. 기본 scheduled_tasks
.
.serializer(Serializer)
작업 데이터를 직렬화할 때 사용할 직렬 변환기 구현입니다. 기본적으로 표준 Java 직렬화를 사용하지만 db-scheduler는 GsonSerializer
및 JacksonSerializer
도 번들로 제공합니다. KotlinSerializer의 예를 참조하세요. 직렬 변환기 아래의 추가 문서도 참조하세요.
.executorService(ExecutorService)
지정된 경우 외부에서 관리되는 이 실행기 서비스를 사용하여 실행을 실행합니다. 이상적으로는 사용할 스레드 수가 계속 제공되어야 합니다(스케줄러 폴링 최적화를 위해). 기본값은 null
.
.deleteUnresolvedAfter(Duration)
알 수 없는 작업이 포함된 실행이 자동으로 삭제되기까지의 시간입니다. 이는 일반적으로 더 이상 사용되지 않는 오래된 반복 작업일 수 있습니다. 이는 구성 오류(알려진 작업 누락) 및 롤링 업그레이드 중 문제로 인해 실수로 작업이 제거되는 것을 방지하기 위해 0이 아닙니다. 기본값은 14d
입니다.
.jdbcCustomization(JdbcCustomization)
db-scheduler는 jdbc 상호 작용을 사용자 정의해야 하는지 확인하는 데 사용되는 데이터베이스를 자동 감지하려고 시도합니다. 이 메소드는 JdbcCustomizations
명시적으로 설정할 수 있는 탈출구입니다. 기본 자동 감지.
.commitWhenAutocommitDisabled(boolean)
기본적으로 DataSource 연결에서는 커밋이 실행되지 않습니다. 자동 커밋이 비활성화된 경우 트랜잭션은 외부 트랜잭션 관리자에 의해 처리되는 것으로 가정됩니다. 이 동작을 재정의하고 스케줄러가 항상 커밋을 실행하도록 하려면 이 속성을 true
로 설정합니다. 기본값은 false
.
.failureLogging(Level, boolean)
작업 실패, 즉 작업 실행 핸들러에서 발생한 Throwable
을 기록하는 방법을 구성합니다. 이러한 종류의 로깅을 완전히 비활성화하려면 로그 수준 OFF
사용하십시오. 기본 WARN, true
.
작업은 Tasks
의 빌더 클래스 중 하나를 사용하여 생성됩니다. 빌더에는 적절한 기본값이 있지만 다음 옵션을 재정의할 수 있습니다.
옵션 | 기본 | 설명 |
---|---|---|
.onFailure(FailureHandler) | 설명을 참조하세요. | ExecutionHandler 예외를 throw할 때 수행할 작업입니다. 기본적으로 반복 작업은 Schedule 에 따라 다시 예약됩니다. 일회성 작업은 5분 후에 다시 시도됩니다. |
.onDeadExecution(DeadExecutionHandler) | ReviveDeadExecution | 죽은 실행( 예: 오래된 하트비트 타임스탬프가 있는 실행)이 감지된 경우 수행할 작업입니다. 기본적으로 중단된 실행은 now() 로 다시 예약됩니다. |
.initialData(T initialData) | null | 반복 작업을 처음 예약할 때 사용할 데이터입니다. |
라이브러리에는 반복 작업을 위한 다양한 일정 구현이 포함되어 있습니다. 수업 Schedules
참조하세요.
일정 | 설명 |
---|---|
.daily(LocalTime ...) | 매일 지정된 시간에 실행됩니다. 선택적으로 시간대를 지정할 수 있습니다. |
.fixedDelay(Duration) | 다음 실행 시간은 마지막 실행이 완료된 후의 Duration 입니다. 참고: 이 Schedule startTasks(...) 에서 사용될 때 Instant.now() 에 대한 초기 실행을 예약합니다. |
.cron(String) | 스프링 스타일 크론 표현(v5.3+). 패턴은 - 비활성화된 일정으로 해석됩니다. |
일정을 구성하는 또 다른 옵션은 Schedules.parse(String)
사용하여 문자열 패턴을 읽는 것입니다.
현재 사용 가능한 패턴은 다음과 같습니다.
무늬 | 설명 |
---|---|
FIXED_DELAY|Ns | 기간이 N초로 설정된 .fixedDelay(Duration) 와 동일합니다. |
DAILY|12:30,15:30...(|time_zone) | 선택적 시간대(예: 유럽/로마, UTC)가 있는 .daily(LocalTime) 와 동일합니다. |
- | 비활성화된 일정 |
시간대 형식에 대한 자세한 내용은 여기에서 확인할 수 있습니다.
Schedule
비활성화된 것으로 표시될 수 있습니다. 스케줄러는 비활성화된 일정이 있는 작업에 대한 초기 실행을 예약하지 않으며 해당 작업에 대한 기존 실행을 제거합니다.
작업 인스턴스는 task_data
필드에 일부 관련 데이터를 가질 수 있습니다. 스케줄러는 Serializer
사용하여 이 데이터를 데이터베이스에 읽고 씁니다. 기본적으로 표준 Java 직렬화가 사용되지만 다양한 옵션이 제공됩니다.
GsonSerializer
JacksonSerializer
Java 직렬화의 경우 데이터를 나타내는 클래스를 발전시킬 수 있도록 serialVersionUID
지정하는 것이 좋습니다. 지정하지 않고 클래스가 변경되면 역직렬화가 InvalidClassException
으로 실패할 가능성이 높습니다. 이런 일이 발생하면 현재 자동 생성된 serialVersionUID
명시적으로 찾아서 설정하세요. 그러면 클래스에 큰 변화가 없는 변경을 수행하는 것이 가능해집니다.
Java 직렬화에서 GsonSerializer
로 마이그레이션해야 하는 경우 SerializerWithFallbackDeserializers
를 사용하도록 스케줄러를 구성합니다.
. serializer ( new SerializerWithFallbackDeserializers ( new GsonSerializer (), new JavaSerializer ()))
Spring Boot 애플리케이션의 경우 스케줄러 연결을 매우 간단하게 만드는 스타터 db-scheduler-spring-boot-starter
가 있습니다. (전체 예제 프로젝트를 참조하세요).
DataSource
입니다. (예제에서는 HSQLDB를 사용하고 스키마가 자동으로 적용됩니다.)< dependency >
< groupId >com.github.kagkarlsson</ groupId >
< artifactId >db-scheduler-spring-boot-starter</ artifactId >
< version >15.0.0</ version >
</ dependency >
Task
를 Spring 빈으로 노출하세요. 반복되는 경우 자동으로 선택되어 시작됩니다.Scheduler
상태를 Actuator 상태 정보에 노출하려면 db-scheduler
상태 표시기를 활성화해야 합니다. 봄 건강정보. 구성은 주로 application.properties
를 통해 수행됩니다. Scheduler-name, serializer 및 executor-service의 구성은 DbSchedulerCustomizer
유형의 Bean을 Spring 컨텍스트에 추가하여 수행됩니다.
# application.properties example showing default values
db-scheduler.enabled=true
db-scheduler.heartbeat-interval=5m
db-scheduler.polling-interval=10s
db-scheduler.polling-limit=
db-scheduler.table-name=scheduled_tasks
db-scheduler.immediate-execution-enabled=false
db-scheduler.scheduler-name=
db-scheduler.threads=10
db-scheduler.priority-enabled=false
# Ignored if a custom DbSchedulerStarter bean is defined
db-scheduler.delay-startup-until-context-ready=false
db-scheduler.polling-strategy=fetch
db-scheduler.polling-strategy-lower-limit-fraction-of-threads=0.5
db-scheduler.polling-strategy-upper-limit-fraction-of-threads=3.0
db-scheduler.shutdown-max-wait=30m
Scheduler
사용하여 지속적인 향후 실행과 상호 작용할 수 있습니다. 전체 Scheduler
인스턴스가 필요하지 않은 상황의 경우 해당 빌더를 사용하여 더 간단한 SchedulerClient를 만들 수 있습니다.
SchedulerClient . Builder . create ( dataSource , taskDefinitions ). build ()
다음과 같은 작업이 가능합니다.
단일 데이터베이스 테이블은 향후 작업 실행을 추적하는 데 사용됩니다. 작업 실행이 예정된 경우 db-scheduler는 이를 선택하여 실행합니다. 실행이 완료되면 Task
참조하여 수행해야 할 작업을 확인합니다. 예를 들어 RecurringTask
는 일반적으로 Schedule
에 따라 향후 일정이 다시 조정됩니다.
스케줄러는 낙관적 잠금 또는 업데이트 선택(폴링 전략에 따라 다름)을 사용하여 하나의 스케줄러 인스턴스만 작업 실행을 선택하고 실행하도록 보장합니다.
반복 작업 이라는 용어는 일부 일정에 따라 정기적으로 실행되어야 하는 작업에 사용됩니다.
반복 작업의 실행이 완료되면 Schedule
참조하여 다음 실행 시간을 결정하고 해당 시간에 대한 향후 작업 실행이 생성됩니다(예: 일정이 다시 조정 됨). 선택한 시간은 Schedule
에 따라 가장 가까운 시간이지만 여전히 미래의 시간입니다.
반복 작업에는 두 가지 유형이 있습니다. Schedule
코드에서 정적으로 정의되는 일반 정적 반복 작업과 Schedule
런타임에 정의되고 데이터베이스에 유지되는 동적 반복 작업(여전히 단일 테이블만 필요함)이 있습니다. .
정적 반복 작업은 가장 일반적이며 정기적인 백그라운드 작업에 적합합니다. 스케줄러가 작업 인스턴스가 없으면 자동으로 예약하고 Schedule
업데이트되면 다음 실행 시간도 업데이트하기 때문입니다.
정적 반복 작업에 대한 초기 실행을 생성하기 위해 스케줄러에는 기존 실행이 아직 없는 경우 "시작"해야 하는 작업 목록을 가져오는 startTasks(...)
메서드가 있습니다. 초기 실행 시간은 Schedule
에 의해 결정됩니다. 작업에 이미 향후 실행이 있지만(예: 이전에 한 번 이상 시작됨) 업데이트된 Schedule
이제 다른 실행 시간을 나타내는 경우 기존 실행이 새 실행 시간으로 다시 예약됩니다( 비결정적 예외 제외). 새로운 실행 시간이 더 먼 미래인 FixedDelay
와 같은 일정)
Tasks.recurring(..)
사용하여 만듭니다.
동적 반복 작업은 나중에 db-scheduler에 추가되었으며 일정이 다른 동일한 유형의 작업(즉, 동일한 구현)의 여러 인스턴스가 필요한 사용 사례를 지원하기 위해 추가되었습니다. Schedule
일반 데이터와 함께 task_data
에 유지됩니다. 정적 반복 작업과 달리 동적 반복 작업은 작업 인스턴스를 자동으로 예약하지 않습니다. 인스턴스를 생성하고 필요한 경우 기존 인스턴스의 일정을 업데이트하는 것은 사용자의 몫입니다( SchedulerClient
인터페이스 사용). 자세한 내용은 RecurringTaskWithPertantScheduleMain.java 예제를 참조하세요.
Tasks.recurringWithPersistentSchedule(..)
사용하여 만듭니다.
일회성 작업이라는 용어는 단일 실행 시간을 갖는 작업에 사용됩니다. 작업 실행의 instanceId
로 데이터를 인코딩하는 것 외에도 실행 시 사용하기 위해 임의의 바이너리 데이터를 별도의 필드에 저장할 수 있습니다. 기본적으로 Java 직렬화는 데이터를 정렬/정렬 해제하는 데 사용됩니다.
Tasks.oneTime(..)
사용하여 생성합니다.
위 카테고리에 맞지 않는 작업의 경우 Tasks.custom(..)
사용하여 작업 동작을 완전히 사용자 정의할 수 있습니다.
사용 사례는 다음과 같습니다.
실행 중에 스케줄러는 작업 실행에 대한 하트비트 시간을 정기적으로 업데이트합니다. 실행이 실행 중인 것으로 표시되었지만 하트비트 시간에 대한 업데이트를 수신하지 못하는 경우 X 시간 이후에는 중단된 실행 으로 간주됩니다. 예를 들어 스케줄러를 실행하는 JVM이 갑자기 종료되는 경우 이런 일이 발생할 수 있습니다.
중단된 실행이 발견되면 수행해야 할 작업을 확인하기 위해 Task
참조합니다. 죽은 RecurringTask
는 일반적으로 now()
로 다시 예약됩니다.
db-scheduler는 처음에 중저 처리량 사용 사례를 대상으로 했지만 데이터 모델이 다음과 같이 매우 단순하다는 사실로 인해 높은 처리량 사용 사례(초당 1000회 이상 실행)를 매우 잘 처리합니다. 단일 실행 테이블. 수행 방법을 이해하려면 일괄 실행별로 실행되는 SQL 문을 고려하는 것이 유용합니다.
원래 및 기본 폴링 전략인 fetch-and-lock-on-execute
다음을 수행합니다.
select
picked=true
로 update
하려고 합니다. 경쟁 스케줄러로 인해 놓칠 수 있습니다.update
delete
.배치당 합계: 1 선택, 2 * 배치 크기 업데이트(누락 제외)
v10에는 새로운 폴링 전략( lock-and-fetch
)이 추가되었습니다. 이는 이제 대부분의 데이터베이스가 SELECT FOR UPDATE
문에서 SKIP LOCKED
지원한다는 사실을 활용합니다(2ndquadrant 블로그 참조). 이러한 전략을 사용하면 사전에 잠긴 실행을 가져오는 것이 가능하므로 명령문을 하나 덜 가져오는 것이 가능합니다.
select for update .. skip locked
. 이는 스케줄러 인스턴스에 의해 이미 선택되어 있습니다.update
하거나 delete
.배치당 합계: 선택 및 업데이트 1회, 배치 크기 업데이트 1회(누락 없음)
db-scheduler에서 기대할 수 있는 사항에 대한 아이디어를 얻으려면 아래 GCP에서 실행된 테스트 결과를 참조하세요. 테스트는 몇 가지 다른 구성으로 실행되었지만 각각은 별도의 VM에서 실행되는 4개의 경쟁 스케줄러 인스턴스를 사용했습니다. TPS는 대략입니다. GCP에 표시된 대로 초당 트랜잭션 수입니다.
처리량 가져오기(예/초) | TPS 가져오기(추정) | 처리량 잠금 및 가져오기(예/초) | TPS 잠금 및 가져오기(예상) | |
---|---|---|---|---|
Postgres 4코어 25GB RAM, 4xVM(2코어) | ||||
스레드 20개, 하위 4.0, 상위 20.0 | 2000 | 9000 | 10600 | 11500 |
100 스레드, 하위 2.0, 상위 6.0 | 2560 | 11000 | 11200 | 11200 |
Postgres 8코어 50GB RAM, 4xVM(4코어) | ||||
스레드 50개, 하위: 0.5, 상위: 4.0 | 4000 | 22000 | 11840 | 10300 |
이 테스트에 대한 관찰:
fetch-and-lock-on-execute
의 경우lock-and-fetch
용 현재 폴링 전략 lock-and-fetch
Postgres에 대해서만 구현됩니다. 더 많은 데이터베이스에 대한 지원을 추가하는 기여를 환영합니다.
높은 처리량 사용 사례를 위해 db-scheduler를 사용하는 사용자가 많이 있습니다. 예를 들면 다음을 참조하세요.
RecurringTask
일정의 모든 인스턴스가 실행된다는 보장은 없습니다. Schedule
은 이전 작업 실행이 완료된 후 참조되며, 다음 실행 시간에는 미래에 가장 가까운 시간이 선택됩니다. 이러한 기능을 제공하기 위해 향후 새로운 유형의 작업이 추가될 수 있습니다.
SchedulerClient
의 메소드( schedule
, cancel
, reschedule
)는 제공된 DataSource
의 새 Connection
사용하여 실행됩니다. 작업이 트랜잭션의 일부가 되도록 하려면 제공된 DataSource
(예: Spring의 TransactionAwareDataSourceProxy
와 같은 것을 사용)에 의해 처리되어야 합니다.
현재 db-scheduler의 정밀도는 테이블에서 적절한 실행을 찾는 빈도를 지정하는 pollingInterval
(기본값 10초)에 따라 다릅니다. 수행 중인 작업을 알고 있는 경우 스케줄러는 런타임 시 scheduler.triggerCheckForDueExecutions()
를 통해 "조기 확인"하도록 지시받을 수 있습니다. ( Builder
의 enableImmediateExecution()
도 참조하세요)
릴리스 노트는 릴리스를 참조하세요.
15.x로 업그레이드
priority
와 인덱스 priority_execution_time_idx
추가해야 한다. postgresql, oracle 또는 mysql에 대한 테이블 정의를 참조하세요. 언젠가는 이 열이 필수 항목이 될 것입니다. 이는 향후 릴리스/업그레이드 노트에서 명확하게 설명될 것입니다.8.x로 업그레이드
boolean isDeterministic()
메서드를 구현해야 합니다.4.x로 업그레이드
consecutive_failures
추가합니다. postgresql, oracle 또는 mysql에 대한 테이블 정의를 참조하세요. null
0으로 처리되므로 기존 레코드를 업데이트할 필요가 없습니다.3.x로 업그레이드
Tasks
클래스의 빌더를 통해 수행하는 것이 바람직합니다.2.x로 업그레이드
task_data
열을 추가합니다. postgresql, oracle 또는 mysql에 대한 테이블 정의를 참조하세요. 전제 조건
다음 단계를 따르세요.
저장소를 복제합니다.
git clone https://github.com/kagkarlsson/db-scheduler
cd db-scheduler
Maven을 사용하여 빌드( -DskipTests=true
추가하여 테스트 건너뛰기)
mvn package
권장사양
일부 사용자는 단일 코어 VM에서 실행할 때 간헐적인 테스트 실패를 경험했습니다. 따라서 최소한 다음을 사용하는 것이 좋습니다.
Quartz
있는데 왜 db-scheduler
사용하는가? db-scheduler
의 목표는 비침투적이고 사용이 간편하면서도 지속성 문제와 클러스터 조정 문제를 해결하는 것입니다. 원래는 11개의 테이블을 추가하는 것이 약간 과도하다고 느낄 수 있는 적당한 데이터베이스 스키마를 갖춘 애플리케이션을 대상으로 했습니다. 업데이트: 또한 현재(2024년) 현재 Quartz는 적극적으로 유지 관리되지 않는 것 같습니다.
키스. 이는 공유 상태 애플리케이션의 가장 일반적인 유형입니다.
기능 요청에 대한 문제를 생성해 주시면 거기서 논의해 보겠습니다. 참을성이 없거나 기여하고 싶다면 풀 요청을 환영합니다 :)
예. 여러 회사에서 생산에 사용되고 있으며 지금까지 원활하게 운영되고 있습니다.