2015-08-12 6 views
12

Ich habe untersucht, wie Sie die Häufigkeit eines Jobs zur Laufzeit mit Java 8 und Spring ändern können. This question war sehr nützlich, aber es löste mein Problem nicht vollständig.Wie gestartete Task zur Laufzeit mit der EnableScheduling-Annotation im Frühjahr neu gestartet werden?

Ich kann jetzt das Datum konfigurieren, wann der Job als nächstes ausgeführt werden soll. Aber wenn die Verzögerung auf 1 Jahr eingestellt ist, dann muss ich 1 Jahr warten, bevor die neue Konfiguration berücksichtigt wird.

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

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äre was ich gerne tun würde.

@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"; 
    } 

} 
+0

Hey +1 für Ihre Frage. Sie sind mit dem Frühling vertraut. Oder brauchst du mich, um auch die Federcodierung zu illustrieren? –

Antwort

5
  1. eine Singleton bean erstellen, die eine injiziert TaskScheduler bekommt. Dies gilt als Statusvariablen alle ScheduledFutures, wie private ScheduledFuture job1;
  2. Bei der Bereitstellung, Laden von Datenbanken alle Daten planen und starten Sie die Jobs, füllen Sie alle Statusvariablen wie job1.
  3. Bei Änderung der Planungsdaten cancel die entsprechende Future (z. B. job1) und starten Sie es dann erneut mit den neuen Planungsdaten.

Die Schlüsselidee hier ist die Kontrolle über die Future s zu erhalten, wie sie erstellt werden, so dass sie in einigen Zustandsvariablen zu speichern, so dass, wenn etwas in Änderungen Planungsdaten, können Sie sie abbrechen. Hier

ist der Arbeitscode:

applicationContext.xml

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

Die Singleton-Bohne, die die

s Future hä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); 
       } 
     } 
} 
0

Ein einfacher Ansatz ist es, nur immer neue Aufgaben hinzufügen Versuchen Sie nicht, den Scheduler abzubrechen oder neu zu starten.

Jedes Mal, wenn sich die Konfiguration ändert, fügen Sie einfach eine neue Aufgabe mit ihrer neuen Konfiguration hinzu.

Wenn ein Task ausgeführt wird, muss er zuerst einen bestimmten Status überprüfen (durch Abfragen der Datenbank oder Nachschlagen in einer gleichzeitigen Map oder was auch immer), um zu entscheiden, ob es sich um die neueste Version handelt. Wenn ja, sollte es weitergehen. Andernfalls sollte es sofort enden.

Der einzige Nachteil ist, dass wenn Sie die Jobkonfiguration häufig ändern, verglichen mit der Häufigkeit, mit der sie ausgeführt werden, dann wird die Liste der geplanten Aufgaben im Speicher immer größer.