Quartz よりも単純なクラスター化されたjava.util.concurrent.ScheduledExecutorService
の必要性から着想を得た Java 用のタスク スケジューラ。
そのため、ユーザー (cbarbosa2、rafaelhofmann、BukhariH) からも高く評価されています。
あなたのライブラリは素晴らしいです! 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 の使用法」を参照してください。
実稼働環境で db-scheduler を実行していることが知られている組織のリスト:
会社 | 説明 |
---|---|
デジポスト | ノルウェーのデジタル メールボックスのプロバイダー |
ヴィグループ | 北欧諸国最大の輸送グループの 1 つ。 |
賢い | 安くて早い海外送金方法。 |
ベッカー専門教育 | |
モニリア | Webサイト監視サービス。 |
ロードスター | Web アプリケーションの負荷テスト。 |
スタテンス・ベグヴェセン | ノルウェー公道管理局 |
ライトイヤー | お金を世界中に投資するためのシンプルで親しみやすい方法です。 |
ナビ | ノルウェー労働福祉局 |
モダンループ | 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 ();
複数のインスタンスとスケジュールを含む繰り返しタスクについては、RecurringTaskWithPersistentScheduleMain.java の例を参照してください。
1 回限りのタスクのインスタンスには、将来のある時点での 1 回の実行時間があります (つまり、非繰り返しです)。インスタンス ID はこのタスク内で一意である必要があり、一部のメタデータ (ID など) をエンコードするために使用される場合があります。より複雑な状態については、カスタムのシリアル化可能な Java オブジェクトがサポートされています (例で使用されているように)。
1 回限りのタスクを定義し、スケジューラを起動します。
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 の機能の一部を示します。スケジュール設定、スケジュールされた実行の取得など。 |
RecurringTaskWithPersistentScheduleMain.java | Schedule task_data の一部として保存される複数インスタンスの定期的なジョブ。たとえば、各テナントに繰り返しタスクが必要なマルチテナント アプリケーションに適しています。 |
StatefulRecurringTaskWithPersistentScheduleMain.java | |
JsonSerializerMain.java | task_data のシリアル化を Java シリアル化 (デフォルト) から JSON にオーバーライドします。 |
JobChainingTaskDataMain.java を使用する | ジョブチェーン、つまり「このインスタンスの実行が完了したら、別のタスクをスケジュールします。 |
JobChainingSeparateTasksMain.java の使用 | 上記のようなジョブチェーン。 |
InterceptorMain.java | ExecutionInterceptor 使用して、すべてのExecutionHandler の実行前後にロジックを挿入します。 |
例 | 説明 |
---|---|
基本的な例 | 基本的な 1 回限りのタスクと定期的なタスク |
トランザクション的にステージングされたジョブ | ジョブをトランザクション的にステージングする例。つまり、トランザクションが (他の DB 変更とともに) コミットされた場合にバックグラウンド ジョブが確実に実行されるようにする。 |
長時間実行ジョブ | 長時間実行されるジョブは、アプリケーションの再起動後も存続し、最初から再起動することを避ける必要があります。この例では、シャットダウン時に進行状況を保持する方法と、さらにジョブを夜間に実行するように制限する手法を示します。 |
定期的な状態追跡 | 実行ごとに状態を変更できる繰り返しタスク。 |
ParallelJobSpawner | 繰り返しジョブを使用して、並列化などの 1 回限りのジョブを生成する方法を示します。 |
ジョブチェーン | 複数のステップを含む 1 回限りのジョブ。次のステップは、前のステップが完了した後にスケジュールされます。 |
マルチインスタンス繰り返し | 同じタイプで、スケジュールやデータが異なる可能性がある複数の定期的なジョブを実現する方法を示します。 |
スケジューラは、 Scheduler.create(...)
ビルダーを使用して作成されます。ビルダーには適切なデフォルト値がありますが、次のオプションは構成可能です。
.threads(int)
スレッドの数。デフォルトは10
。
.pollingInterval(Duration)
スケジューラがデータベースの実行期限をチェックする頻度。デフォルトは10s
。
.alwaysPersistTimestampInUTC()
スケジューラは、タイムスタンプを保持する列がLocalDateTime
ではなくInstant
を保持する、つまり何らかの方法でタイムスタンプをゾーンに結び付けると想定します。ただし、一部のデータベースでは、そのような型 (ゾーン情報を持たない) やその他の特殊なタイプのサポートが制限されているため、「常に UTC に保存する」方がより良い代替手段となります。このような場合には、この設定を使用してインスタントを常に UTC で保存します。 PostgreSQL および Oracle スキーマは、ゾーン情報を保持するためにテストされています。 MySQLおよびMariaDBスキーマはこの設定を使用しませんし、使用する必要があります。注意:下位互換性のため、「不明」データベースのデフォルトの動作では、データベースがタイムゾーンを保持していると想定されます。 「既知の」データベースについては、クラスAutodetectJdbcCustomization
を参照してください。
.enableImmediateExecution()
これが有効な場合、スケジューラは、 now()
の実行がスケジュールされた後、または過去の時刻に実行される実行があることをローカルScheduler
に通知しようとします。注意: schedule(..)
/ reschedule(..)
への呼び出しがトランザクション内から発生した場合、スケジューラは更新が表示される前 (トランザクションがコミットされていない) にそれを実行しようとする可能性があります。ただし、まだ永続化されているため、失敗した場合でも、次のpolling-interval
の前に実行されます。スケジューラ メソッドのscheduler.triggerCheckForDueExecutions()
) を使用して、期限切れの実行の早期チェックをプログラムでトリガーすることもできます。デフォルトはfalse
。
.registerShutdownHook()
シャットダウン時にScheduler.stop()
を呼び出すシャットダウン フックを登録します。正常にシャットダウンし、デッド実行を回避するには、常に 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
、データベース (低または高) に応じて解釈が異なる場合があります。 1 秒あたり 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)
select for update .. skip locked
使用するlock-and-fetch
ポーリング戦略を使用します。オーバーヘッドを軽減するためにロックをスキップします。
データベースからの最後のフェッチがフルバッチだった場合、残りの実行数がlowerLimitFractionOfThreads * nr-of-threads
以下になると、新しいフェッチがトリガーされます。毎回フェッチされる実行数は(upperLimitFractionOfThreads * nr-of-threads) - nr-executions-left
に等しくなります。フェッチされた実行は、このスケジューラ インスタンスに対してすでにロック/選択されているため、 UPDATE
ステートメントが 1 つ節約されます。
通常の使用では、たとえば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)
不明なタスクによる実行が自動的に削除されるまでの時間。これらは通常、もう使用されていない古い定期的なタスクである可能性があります。これは、構成エラー (既知のタスクの欠落) やローリング アップグレード中の問題による誤ったタスクの削除を防ぐために、ゼロ以外の値に設定されます。デフォルトは14d
です。
.jdbcCustomization(JdbcCustomization)
db-scheduler は、jdbc インタラクションをカスタマイズする必要があるかどうかを確認するために使用されるデータベースを自動検出しようとします。このメソッドは、 JdbcCustomizations
明示的に設定できるようにするためのエスケープ ハッチです。デフォルトの自動検出。
.commitWhenAutocommitDisabled(boolean)
デフォルトでは、DataSource 接続に対してコミットは発行されません。自動コミットが無効になっている場合、トランザクションは外部トランザクション マネージャーによって処理されると想定されます。この動作をオーバーライドし、スケジューラが常にコミットを発行するには、このプロパティをtrue
に設定します。デフォルトはfalse
。
.failureLogging(Level, boolean)
タスクの失敗、つまりタスク実行ハンドラーからスローされたThrowable
をログに記録する方法を構成します。この種のログを完全に無効にするには、ログ レベルOFF
使用します。デフォルトのWARN, true
。
タスクはTasks
のビルダークラスの 1 つを使用して作成されます。ビルダーには適切なデフォルト値がありますが、次のオプションはオーバーライドできます。
オプション | デフォルト | 説明 |
---|---|---|
.onFailure(FailureHandler) | 説明を参照してください。 | ExecutionHandler 例外をスローした場合の対処方法。デフォルトでは、定期的なタスクはSchedule に従って再スケジュールされ、1 回限りのタスクは5 分後に再試行されます。 |
.onDeadExecution(DeadExecutionHandler) | ReviveDeadExecution | 無効な実行、つまり、古いハートビート タイムスタンプを持つ実行が検出された場合に何を行うか。デフォルトでは、デッド実行はnow() に再スケジュールされます。 |
.initialData(T initialData) | null | 定期的なタスクを初めてスケジュールするときに使用するデータ。 |
ライブラリには、定期的なタスクのための多数のスケジュール実装が含まれています。クラスSchedules
を参照してください。
スケジュール | 説明 |
---|---|
.daily(LocalTime ...) | 毎日指定された時刻に実行されます。オプションでタイムゾーンを指定できます。 |
.fixedDelay(Duration) | 次の実行時間は、最後に実行が完了してからのDuration です。注:このSchedule 、 startTasks(...) で使用される場合、 Instant.now() への初期実行をスケジュールします。 |
.cron(String) | Spring スタイルの cron 式 (v5.3 以降)。パターン- は無効なスケジュールとして解釈されます。 |
スケジュールを構成する別のオプションは、 Schedules.parse(String)
を使用して文字列パターンを読み取ることです。
現在利用可能なパターンは次のとおりです。
パターン | 説明 |
---|---|
FIXED_DELAY|Ns | 期間を N 秒に設定した.fixedDelay(Duration) と同じです。 |
DAILY|12:30,15:30...(|time_zone) | オプションのタイムゾーンを備えた.daily(LocalTime) と同じ (ヨーロッパ/ローマ、UTC など) |
- | 無効なスケジュール |
タイムゾーン形式の詳細については、ここを参照してください。
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 Bean として公開します。繰り返し発生する場合は、自動的に取得されて開始されます。Scheduler
状態をアクチュエータの健全性情報に公開したい場合は、 db-scheduler
健全性インジケータを有効にする必要があります。春の健康情報。設定は主にapplication.properties
を介して行われます。スケジューラ名、シリアライザ、およびエグゼキュータ サービスの構成は、 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
に基づいて将来に再スケジュールされます。
スケジューラは、オプティミスティック ロックまたは select-for-update (ポーリング戦略に応じて) を使用して、1 つだけのスケジューラ インスタンスがタスク実行を選択して実行できることを保証します。
定期的なタスクという用語は、何らかのスケジュールに従って定期的に実行する必要があるタスクに使用されます。
定期的なタスクの実行が終了すると、 Schedule
が参照されて次回の実行時間が決定され、その時間に対して将来のタスク実行が作成されます (つまり、再スケジュールされます)。選択される時間は、 Schedule
に従って最も近い時間ですが、まだ将来の時間です。
定期的なタスクには 2 つのタイプがあります。1 つは通常の静的な繰り返しタスクで、 Schedule
コード内で静的に定義されます。もう 1 つは動的繰り返しタスクで、 Schedule
実行時に定義され、データベースに保持されます (必要なテーブルは 1 つだけです)。 。
静的繰り返しタスクは最も一般的なタスクであり、タスクのインスタンスが存在しない場合はスケジューラが自動的にスケジュールを設定し、 Schedule
が更新された場合は次回の実行時刻も更新するため、通常のバックグラウンド ジョブに適しています。
静的繰り返しタスクの最初の実行を作成するために、スケジューラには、既存の実行がない場合に「開始」する必要があるタスクのリストを取得するメソッドstartTasks(...)
があります。初期実行時間はSchedule
によって決まります。タスクに将来の実行がすでにある (つまり、以前に少なくとも 1 回開始されている) が、更新されたSchedule
別の実行時間を示している場合、既存の実行は新しい実行時間に再スケジュールされます (非決定的な実行時間を除く)。新しい実行時間がさらに先になる、 FixedDelay
などのスケジュール)。
Tasks.recurring(..)
を使用して作成します。
動的繰り返しタスクは、後で db-scheduler に追加されたもので、異なるスケジュールを持つ同じタイプのタスク (つまり、同じ実装) の複数のインスタンスが必要なユースケースをサポートするために追加されました。 Schedule
、通常のデータとともにtask_data
に保存されます。静的な繰り返しタスクとは異なり、動的タスクではタスクのインスタンスが自動的にスケジュールされません。インスタンスを作成し、必要に応じて既存のスケジュールを更新するのはユーザーの責任です ( SchedulerClient
インターフェイスを使用)。詳細については、RecurringTaskWithPersistentScheduleMain.java の例を参照してください。
Tasks.recurringWithPersistentSchedule(..)
を使用して作成します。
ワンタイムタスクという用語は、実行時間が 1 回であるタスクを指します。データをタスク実行のinstanceId
にエンコードすることに加えて、実行時に使用するために任意のバイナリ データを別のフィールドに保存することができます。デフォルトでは、データのマーシャリング/アンマーシャリングに Java シリアル化が使用されます。
Tasks.oneTime(..)
を使用して作成します。
上記のカテゴリに当てはまらないタスクについては、 Tasks.custom(..)
を使用してタスクの動作を完全にカスタマイズできます。
使用例は次のとおりです。
実行中、スケジューラはタスク実行のハートビート時間を定期的に更新します。実行が実行中としてマークされているが、ハートビート時間の更新を受信していない場合、その実行は時間 X 以降に無効な実行とみなされます。これは、たとえば、スケジューラを実行している JVM が突然終了した場合に発生する可能性があります。
デッド実行が見つかると、 Task
が参照されて、何をすべきかが確認されます。デッドRecurringTask
は通常、 now()
に再スケジュールされます。
db-scheduler は当初、低から中程度のスループットのユースケースを対象としていましたが、データ モデルが非常にシンプルで、以下で構成されているため、高スループットのユースケース (1 秒あたり 1000 回以上の実行) にも非常によく対応します。単一の実行テーブル。どのように実行されるかを理解するには、実行バッチごとに実行される SQL ステートメントを考慮すると役立ちます。
元のデフォルトのポーリング戦略fetch-and-lock-on-execute
次のことを行います。
select
picked=true
にupdate
うとします。スケジューラの競合により欠席する可能性があります。update
またはdelete
。バッチごとの合計: 1 選択、2 * バッチサイズ更新 (ミスを除く)
v10 では、新しいポーリング戦略 ( lock-and-fetch
) が追加されました。これは、ほとんどのデータベースがSELECT FOR UPDATE
ステートメントでSKIP LOCKED
をサポートしているという事実を利用しています (第 2 象限のブログを参照)。このような戦略を使用すると、事前にロックされた実行をフェッチできるため、取得するステートメントが 1 つ少なくなります。
select for update .. skip locked
。これらはスケジューラ インスタンスによってすでに選択されています。update
またはdelete
。バッチごとの合計: 1 回の選択と更新、1 * バッチサイズの更新 (ミスなし)
db-scheduler に何が期待できるかを知るには、以下の GCP で実行されたテストの結果を参照してください。テストはいくつかの異なる構成で実行されましたが、それぞれが別の VM 上で実行される 4 つの競合するスケジューラー インスタンスを使用しました。 TPS はおよそです。 GCP で示される 1 秒あたりのトランザクション数。
スループットフェッチ (例/秒) | TPS フェッチ (推定) | スループットのロックアンドフェッチ (ex/s) | 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
を使用して実行されます。アクションをトランザクションの一部にするには、たとえば Spring のTransactionAwareDataSourceProxy
などを使用して、提供されたDataSource
によって処理される必要があります。
現在、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 も積極的にメンテナンスされていないようです。
キス。これは、アプリケーションが持つ最も一般的なタイプの共有状態です。
機能リクエストで問題を作成してください。そこで議論できます。せっかちな方 (または貢献したいと思っている方) はプルリクエストを大歓迎です :)
はい。多くの企業の本番環境で使用されており、これまでのところ順調に稼働しています。