5秒の固定遅延でトリガーするスケジューラがあります。
複数のスケジューラを計画していますが、今のところ、1つのスケジューラのみに固執しましょう。
要件:ビジネス条件スケジューラーのfixedDelayに基づいて変更する必要があります。
**例、**デフォルトfixedDelayは5secsですが、6、8、10秒、条件に基づく。
これを実現するために、fixedDelayを変更しようとしています。しかし、それは私のために働いていません。
コード:
インターフェイス、遅延メソッドあり。
public abstract class DynamicSchedule{
/**
* Delays scheduler
* @param milliseconds - the time to delay scheduler.
*/
abstract void delay(Long milliseconds);
/**
* Decreases delay period
* @param milliseconds - the time to decrease delay period.
*/
abstract void decreaseDelayInterval(Long milliseconds);
/**
* Increases delay period
* @param milliseconds - the time to increase dela period
*/
abstract void increaseDelayInterval(Long milliseconds);
}
spring-contextプロジェクトのorg.springframework.schedulingにあるTriggerインターフェースを実装する。
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import Java.util.Date;
import Java.util.concurrent.ScheduledFuture;
public class CustomDynamicSchedule extends DynamicSchedule implements Trigger {
private TaskScheduler taskScheduler;
private ScheduledFuture<?> schedulerFuture;
/**
* milliseconds
*/
private long delayInterval;
public CustomDynamicSchedule(TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
@Override
public void increaseDelayInterval(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval += delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
@Override
public void decreaseDelayInterval(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval += delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
@Override
public void delay(Long delay) {
if (schedulerFuture != null) {
schedulerFuture.cancel(true);
}
this.delayInterval = delay;
schedulerFuture = taskScheduler.schedule(() -> { }, this);
}
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
Date lastTime = triggerContext.lastActualExecutionTime();
return (lastTime == null) ? new Date() : new Date(lastTime.getTime() + delayInterval);
}
}
構成:
@Configuration
public class DynamicSchedulerConfig {
@Bean
public CustomDynamicSchedule getDinamicScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.initialize();
return new CustomDynamicSchedule(threadPoolTaskScheduler);
}
}
テストクラス。使用法をテストします。
@EnableScheduling
@Component
public class TestSchedulerComponent {
@Autowired
private CustomDynamicSchedule dynamicSchedule;
@Scheduled(fixedDelay = 5000)
public void testMethod() {
dynamicSchedule.delay(1000l);
dynamicSchedule.increaseDelayInterval(9000l);
dynamicSchedule.decreaseDelayInterval(5000l);
}
}
私は https://stackoverflow.com/a/51333059/4770397 の助けを借りました
しかし、残念ながら、このコードは私には機能しません。
スケジューラはfixedDelayで実行されているため、変更はありません。
助けてください..
@Scheduled
を使用すると、静的なスケジュールのみを使用できます。プロパティを使用して、このようにスケジュールを構成可能にすることができます
@Scheduled(cron = "${yourConfiguration.cronExpression}")
// or
@Scheduled(fixedDelayString = "${yourConfiguration.fixedDelay}")
ただし、春のコンテキストが初期化されると(アプリケーションが開始されると)、結果のスケジュールは修正されます。
スケジュールされた実行をきめ細かく制御するには、カスタム Trigger
を実装する必要があります。実行されるタスクとともに、このトリガーは @Configuration
を使用してScheduledTaskRegistrar.addTriggerTask
クラスに SchedulingConfigurer
を実装することで登録できます。
@Configuration
@EnableScheduling
public class AppConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
taskRegistrar.addTriggerTask(() -> myTask().work(), myTrigger());
}
@Bean(destroyMethod="shutdown")
public Executor taskScheduler() {
return Executors.newScheduledThreadPool(42);
}
@Bean
public CustomDynamicSchedule myTrigger() {
new CustomDynamicSchedule();
}
@Bean
public MyTask myTask() {
return new MyTask();
}
}
ただし、CustomDynamicSchedule
でのタスクの登録は行わず、次の実行時間を計算するために使用するだけです。
public class CustomDynamicSchedule extends DynamicSchedule implements Trigger {
private long delayInterval;
@Override
public synchronized void increaseDelayInterval(Long delay) {
this.delayInterval += delay;
}
@Override
public synchronized void decreaseDelayInterval(Long delay) {
this.delayInterval += delay;
}
@Override
public synchronized void delay(Long delay) {
this.delayInterval = delay;
}
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
Date lastTime = triggerContext.lastActualExecutionTime();
return (lastTime == null) ? new Date() : new Date(lastTime.getTime() + delayInterval);
}
}
ただし、CustomDynamicSchedule
スレッドは、スプリングによってシングルトンとして作成され、複数のスレッドによって並行してアクセスされる可能性があるため、スレッドセーフにすることを忘れないでください。
注釈を使用すると、一般的な分母を見つけてそれをポーリングすることにより、近似によってのみそれを行うことができます。後でお見せします。実際の動的ソリューションが必要な場合は、アノテーションは使用できませんが、プログラムによる構成を使用できます。 このソリューションの良い点は、実行時でも実行期間を変更できることです!これを行う方法の例を次に示します。
public initializeDynamicScheduledTAsk (ThreadPoolTaskScheduler scheduler,Date start,long executionPeriod) {
scheduler.schedule(
new ScheduledTask(),
new Date(startTime),period
);
}
class ScheduledTask implements Runnable{
@Override
public void run() {
// my scheduled logic here
}
}
注釈を付けて実際に何かをする方法があります。しかし、精度が重要でない場合にのみ、これを行うことができます。精度とはどういう意味ですか。 5秒ごとに開始することがわかっているが、100ms程度は重要ではない場合。 5-6-8または10秒ごとに開始する必要があることがわかっている場合は、毎秒実行される1つのジョブを構成し、1つのifステートメント内で前回の実行からの経過時間を確認できます。それは非常に不十分ですが、ミリ秒までの精度を必要としない限り:)機能します。次に例を示します。
public class SemiDynamicScheduledService {
private Long lastExecution;
@Value(#{yourDynamicConfiguration})
private int executeEveryInMS
@Scheduled(fixedDelay=1000)
public semiDynamicScheduledMethod() {
if (System.currentTimeMS() - lastExecution>executeEveryInMS) {
lastExecution = System.currentTimeMS();
// put your processing logic here
}
}
}
私は少し下手ですが、単純なケースでは仕事をします。
春の@Scheduled
アノテーションはこのサポートを提供しません。
これは、タイミングの柔軟性とこのスケジューラ機能の非常に堅牢な実装を可能にするキューベースのソリューションを使用した、同様の機能の私の好ましい実装です。
cron
と、メッセージのパブリッシュを担当するシングルスレッドのエグゼキューターサービスがありますクーロンごとにキューに。 task-cron
マッピングはdatabase
に保持され、起動時に初期化されます。また、実行時にタスクのcronを更新するためにAPI
が公開されています。APIを介してcronの変更をトリガーするたびに、古いスケジュール済みのexecutorサービスをシャットダウンし、作成します。また、データベース内でも同じように更新します。
このアプローチにはさまざまな利点があります。これにより、スケジューラがスケジュール管理タスクから切り離されます。これで、スケジューラはビジネスロジックのみに集中できます。また、必要な数のスケジューラを記述して、すべて同じキューをリッスンし、それに応じて動作させることができます。