it-swarm.com.de

Wie starte ich einen geplanten Task zur Laufzeit mit EnableScheduling Annotation im Frühjahr neu?

Ich habe untersucht, wie ich die Häufigkeit eines Jobs zur Laufzeit mit Java 8 und spring ändern kann. Diese Frage war sehr nützlich, aber es hat mein Problem nicht vollständig gelöst.

Ich kann jetzt das Datum konfigurieren, an dem der Auftrag als nächstes ausgeführt werden soll. Aber wenn die Verzögerung auf 1 Jahr festgelegt, dann muss ich 1 Jahr warten, bevor die neue Konfiguration in berücksichtigt.

Meine Idee wäre, die geplante Aufgabe zu stoppen, wenn der Konfigurationswert (so von einer anderen Klasse) geändert wird. Berechnen Sie dann das nächste Mal neu, wenn die Aufgabe ausgeführt werden soll. Vielleicht gibt es dafür einen einfacheren Weg.

Hier ist der Code, den ich bisher habe.

@Configuration
@EnableScheduling
public class RequestSchedulerConfig implements SchedulingConfigurer {

    @Autowired
    SchedulerConfigService schedulerConfigService;

    @Bean
    public RequestScheduler myBean() {
        return new RequestScheduler();
    }

    @Bean(destroyMethod = "shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(100);
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
        taskRegistrar.addTriggerTask(
                new Runnable() {
                    @Override public void run() {
                        myBean().startReplenishmentComputation();
                    }
                },
                new Trigger() {
                    @Override public Date nextExecutionTime(TriggerContext triggerContext) {
                        Duration d = schedulerConfigService.getIntervalFromDB();
                        return DateTime.now().plus(d).toDate();
                    }
                }
        );
    }
}

Das würde ich gerne tun.

@RestController
@RequestMapping("/api/config/scheduler")
public class RequestSchedulerController {

    @Autowired
    ApplicationConfigWrapper applicationConfigWrapper;

    @RequestMapping("/set/")
    @ResponseBody
    public String setRequestSchedulerConfig(@RequestParam(value = "frequency", defaultValue = "") final String frequencyInSeconds){
        changeValueInDb(frequencyInSeconds);
        myJob.restart();
        return "Yeah";
    }

}
13
Paul Fournel
  1. Erstellen Sie eine Singleton-Bean, die ein injiziertes TaskScheduler erhält. Dies wird als Statusvariablen alle ScheduledFutures enthalten, wie private ScheduledFuture job1;
  2. Laden Sie bei der Bereitstellung alle Zeitplandaten aus den Datenbanken und starten Sie die Jobs. Geben Sie dabei alle Statusvariablen wie job1 ein.
  3. Bei Änderung der Planungsdaten Abbrechen das entsprechende Future (z. B. job1) und starten Sie es dann erneut mit den neuen Planungsdaten.

Die Schlüsselidee hierbei ist, die Kontrolle über die Futures zu erlangen, wenn sie erstellt werden, um sie in einigen Statusvariablen zu speichern, sodass Sie sie abbrechen können, wenn sich etwas in der Zeitplanung ändert.

Hier ist der Arbeitscode:

applicationContext.xml

<task:annotation-driven />
<task:scheduler id="infScheduler" pool-size="10"/>

Die Singleton-Bean, die die Futures enthält

@Component
public class SchedulerServiceImpl implements SchedulerService {

        private static final Logger logger = LoggerFactory.getLogger(SchedulerServiceImpl.class);

        @Autowired
        @Qualifier(value="infScheduler")
        private TaskScheduler taskScheduler;

        @Autowired
        private MyService myService;

        private ScheduledFuture job1;//for other jobs you can add new private state variables

        //Call this on deployment from the ScheduleDataRepository and everytime when schedule data changes.
        @Override
        public synchronized void scheduleJob(int jobNr, long newRate) {//you are free to change/add new scheduling data, but suppose for now you only want to change the rate
                if (jobNr == 1) {//instead of if/else you could use a map with all job data
                        if (job1 != null) {//job was already scheduled, we have to cancel it
                                job1.cancel(true);
                        }
                        //reschedule the same method with a new rate
                        job1 = taskScheduler.scheduleAtFixedRate(new ScheduledMethodRunnable(myService, "methodInMyServiceToReschedule"), newRate);
                }
        }
}
5
Andrei I

Ein einfacher Ansatz besteht darin, immer nur neue Aufgaben hinzuzufügen und nicht zu versuchen, den Scheduler abzubrechen oder neu zu starten.

Bei jeder Änderung der Konfiguration fügen Sie einfach eine neue Aufgabe mit der neuen Konfiguration hinzu.

Wenn eine Aufgabe ausgeführt wird, muss sie zunächst einen Status überprüfen (indem sie die Datenbank abfragt oder in einer gleichzeitigen Zuordnung nachschlägt oder was auch immer), um zu entscheiden, ob es sich um die neueste Version handelt. Wenn ja, dann sollte es weitergehen. Andernfalls sollte es sofort enden.

Der einzige Nachteil ist, dass die Liste der geplanten Aufgaben im Arbeitsspeicher weiter wächst, wenn Sie die Auftragskonfiguration im Vergleich zu der Häufigkeit, mit der sie ausgeführt werden, häufig ändern.

0
drrob

Was ist mit Set<ScheduledTask> ScheduledTaskRegistrar.getScheduledTasks(), um alle Zeitplanaufgaben abzurufen und ScheduledTask::cancel() aufzurufen? oder möglicherweise ThreadPoolTaskScheduler::shutdown() ausführen und ThreadPoolTaskScheduler erneut erstellen und in ScheduledTaskRegistrar erneut festlegen?

0
razor