SpringQquartzから20秒ごとに実行されるJavaプログラムがあります。実行に数秒かかることもありますが、データが大きくなるにつれて、20秒以上実行されると確信しています。
1つのインスタンスがまだ実行されているときに、Quartzがジョブを起動/トリガーしないようにするにはどうすればよいですか?データベースで同じ操作を実行する2つのジョブを実行するのは、あまり良くありません。ある種の同期を行う方法はありますか?
SpringQquartzから20秒ごとに実行されるJavaプログラムがあります。実行に数秒かかることもありますが、データが大きくなるにつれて、20秒以上実行されると確信しています。
1つのインスタンスがまだ実行されているときに、Quartzがジョブを起動/トリガーしないようにするにはどうすればよいですか?データベースで同じ操作を実行する2つのジョブを実行するのは、あまり良くありません。ある種の同期を行う方法はありますか?
JobではなくStatefulJobを実装するようにクラスを変更すると、Quartzがこれを処理します。StatefulJob javadocから:
ステートフルジョブを同時に実行することはできません。つまり、execute(xx)メソッドの完了前に発生する新しいトリガーが遅延します。
StatefulJobはJobを拡張し、新しいメソッドを追加しないため、必要な動作を取得するために必要なのは、これを変更することだけです。
public class YourJob implements org.quartz.Job {
void execute(JobExecutionContext context) {/*implementation omitted*/}
}
これに:
public class YourJob implements org.quartz.StatefulJob {
void execute(JobExecutionContext context) {/*implementation omitted*/}
}
Quartzのバージョン2.0では、StatefulJob
非推奨になりました。代わりに注釈を使用することをお勧めします。
@DisallowConcurrentExecution
public class YourJob implements org.quartz.Job {
void execute(JobExecutionContext context) {/*implementation omitted*/}
}
あなたがする必要があるのが20秒ごとに発砲することだけであるならば、クォーツは深刻なやり過ぎです。そのjava.util.concurrent.ScheduledExecutorService
仕事には完全に十分なはずです。
はScheduledExecutorService
、スケジューリングのための2つのセマンティクスも提供します。「固定レート」はオーバーラップに関係なく20秒ごとにジョブを実行しようとしますが、「固定遅延」は最初のジョブの終了から次のジョブの開始まで20秒を残そうとします。オーバーラップを避けたい場合は、固定遅延が最も安全です。
誰かがこの質問を参照する場合に備えて、StatefulJobは非推奨になりました。代わりに注釈を使用することをお勧めします...
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class TestJob implements Job {
これは、それらの注釈が何を意味するかを説明します...
アノテーションは、その名前が示すとおりの動作を引き起こします-ジョブの複数のインスタンスを同時に実行することは許可されません(ジョブのexecute()メソッドに実行に34秒かかるコードが含まれているが、 30秒ごとに繰り返されるトリガー)、実行のたびにそのJobDataMapの内容がスケジューラーのJobStoreに再永続化されます。この例では、@ PersistJobDataAfterExecutionアノテーションのみが真に関連していますが、保存されたデータの競合状態を防ぐために、@DisallowConcurrentExecutionアノテーションを使用することをお勧めします。
スプリングクォーツを使用する場合は、このように構成する必要があると思います
<bean id="batchConsumerJob"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myScheduler" />
<property name="targetMethod" value="execute" />
<property name="concurrent" value="false" />
</bean>
2番目のタスクは最初のタスクが完了するまでブロックされ、バックログが発生するため、同期が必要かどうかはわかりません。ジョブをキューに入れることもできますが、説明からすると、キューが無期限に大きくなる可能性があるようです。
ReadWriteLockを調査し、実行中にタスクにロックを設定させます。将来のタスクはこのロックを検査し、古いタスクがまだ実行されている場合はすぐに終了できます。私は経験から、これがこれに取り組むための最も信頼できる方法であることがわかりました。
おそらく、警告も生成するので、問題が発生していることがわかり、それに応じて時間間隔を長くしますか?
それらをキューに入れます
時間が20秒を超えた場合でも、現在のジョブを終了してから、次のジョブをキューからフェッチする必要があります。
または、時間をある程度まで増やすこともできます。
セマフォを使用できます。セマフォが取得されたら、2番目のジョブを放棄し、次の発砲時刻まで待ちます。