2015-08-12 89 views
12

Ho studiato come modificare la frequenza di un lavoro in runtime con Java 8 e Spring. This question è stato molto utile ma non ha risolto completamente il mio problema.Come riavviare l'attività pianificata in runtime con l'annotazione EnableScheduling in primavera?

Ora posso configurare la data in cui il lavoro deve essere eseguito successivamente. Ma se imposta il ritardo su 1 anno, allora devo aspettare 1 anno prima che la nuova configurazione venga presa in considerazione.

La mia idea sarebbe quella di interrompere l'attività pianificata se il valore di configurazione è cambiato (quindi da un'altra classe). Quindi ricalcolare la prossima volta che l'attività dovrebbe essere eseguita. Forse c'è un modo più semplice per farlo.

Ecco il codice che ho finora.

@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(); 
        } 
       } 
     ); 
    } 
} 

Questo sarebbe quello che mi piacerebbe fare.

@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 per la tua domanda. Sei abituato alla primavera. oppure u bisogno di me per illustrare la codifica primavera anche ?? –

risposta

5
  1. Creare un fagiolo Singleton che ottiene un iniettato TaskScheduler. Ciò si manterrà come variabili di stato tutte- In caso di distribuzione, caricare dai database tutti i dati di pianificazione e avviare i lavori, compilando tutte le variabili di stato come job1.
  2. In caso di modifica dei dati di pianificazione, cancel corrispondente Future (ad esempio job1), quindi riavviarlo con i nuovi dati di pianificazione.

L'idea chiave qui è quello di ottenere il controllo sulle Future s come sono creati, in modo per salvarli in alcune variabili di stato, in modo che quando qualcosa in modifiche dei dati di pianificazione, è possibile cancellarli.

Ecco il codice di lavoro:

applicationContext.xml

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

Il fagiolo Singleton, che detiene la Future s

@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

Un approccio semplice è quello di sempre e solo aggiungere nuove attività , non per cercare di annullare o riavviare il programma di pianificazione.

Ogni volta che le modifiche di configurazione, è sufficiente aggiungere una nuova attività con la sua nuova configurazione.

Quindi, ogni volta che viene eseguita un'attività, è necessario prima controllare alcuni stati (eseguendo query sul database, o cercando in una mappa concorrente, o qualsiasi altra cosa) per decidere se è l'ultima versione. Se lo è, allora dovrebbe procedere. Altrimenti, dovrebbe finire immediatamente.

L'unico inconveniente è che se si modifica la configurazione del processo di frequente rispetto a quanto spesso corrono, poi, naturalmente, la lista delle attività pianificate continuerà a crescere in memoria.