web-dev-qa-db-fra.com

Planification programmée d'un travail avec Spring (avec fixedRate défini de manière dynamique)

Actuellement j'ai ceci:

@Scheduled(fixedRate=5000)
public void getSchedule(){
   System.out.println("in scheduled job");
}

Je pourrais changer cela pour utiliser une référence à une propriété

@Scheduled(fixedRate=${myRate})
public void getSchedule(){
   System.out.println("in scheduled job");
}

Cependant, je dois utiliser une valeur obtenue par programme pour que la planification puisse être modifiée sans redéployer l'application. Quel est le meilleur moyen? Je me rends compte que l'utilisation d'annotations peut ne pas être possible ...

60
NimChimpsky

En utilisant Trigger , vous pouvez calculer le prochain temps d'exécution à la volée.

Quelque chose comme ça devrait faire l'affaire (adapté de Javadoc pour @EnableScheduling ):

@Configuration
@EnableScheduling
public class MyAppConfig implements SchedulingConfigurer {

    @Autowired
    Environment env;

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

    @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().getSchedule();
                    }
                },
                new Trigger() {
                    @Override public Date nextExecutionTime(TriggerContext triggerContext) {
                        Calendar nextExecutionTime =  new GregorianCalendar();
                        Date lastActualExecutionTime = triggerContext.lastActualExecutionTime();
                        nextExecutionTime.setTime(lastActualExecutionTime != null ? lastActualExecutionTime : new Date());
                        nextExecutionTime.add(Calendar.MILLISECOND, env.getProperty("myRate", Integer.class)); //you can get the value from wherever you want
                        return nextExecutionTime.getTime();
                    }
                }
        );
    }
}
103
ach

Aussi, vous pouvez utiliser cette approche simple:

private int refreshTickNumber = 10;
private int tickNumber = 0; 

@Scheduled(fixedDelayString = "${some.rate}")
public void NeXTSTEP() {
    if (tickNumber < refreshTickNumber) {
        tickNumber++;
        return;
    }
    else {
        tickNumber = 0;
    }
    // some code
}

refreshTickNumber est entièrement configurable à l'exécution et peut être utilisé avec @Value annotation.

6
Praytic

vous pouvez gérer le redémarrage de la planification à l'aide de TaskScheduler et ScheduledFuture:

@Configuration
@EnableScheduling
@Component
public class CronConfig implements SchedulingConfigurer , SchedulerObjectInterface{

    @Autowired
    private ScheduledFuture<?> future;

     @Autowired
        private TaskScheduler scheduler;

    @Bean
    public SchedulerController schedulerBean() {
        return new SchedulerController();
    }

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

        @Override
    public void start() {
        future = scheduler.schedule(new Runnable() {
            @Override
            public void run() {
                //System.out.println(JOB + "  Hello World! " + new Date());
                schedulerBean().schedulerJob();
            }
        }, new Trigger() {
            @Override public Date nextExecutionTime(TriggerContext triggerContext) {
                Calendar nextExecutionTime =  new GregorianCalendar();
                Date lastActualExecutionTime = triggerContext.lastActualExecutionTime(); 
           nextExecutionTime.setTime(convertExpresssiontoDate());//you can get the value from wherever you want
                return nextExecutionTime.getTime();
            }
        });

    }


    @Override
    public void stop() {
        future.cancel(true);

    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        // TODO Auto-generated method stub
        start();
    }

}

interface pour start stop:

public interface SchedulerObjectInterface {    
    void start();
    void stop();
}

maintenant, vous pouvez arrêter et recommencer (redémarrer) Planification à l'aide de @Autowired SchedulerObjectInterface

4
Sandip Solanki

Exemple de démarrage simplifié limité à des intervalles de secondes, de minutes et d’heures. L’intention de cet exemple est de démontrer le traitement conditionnel de deux propriétés, TimeUnit et interval.

Propriétés:

snapshot.time-unit=SECONDS
snapshot.interval=5

Méthode programmée:

@Scheduled(cron = "*/1 * * * * *")
protected void customSnapshotScheduler()
{
    LocalDateTime now = LocalDateTime.now();
    TimeUnit timeUnit = TimeUnit.valueOf(snapshotProperties.getSnapshot().getTimeUnit());
    int interval = snapshotProperties.getSnapshot().getInterval();

    if (TimeUnit.SECONDS == timeUnit
            && now.getSecond() % interval == 0)
    {
        this.camService.writeSnapshot(webcam.getImage());
    }

    if (TimeUnit.MINUTES == timeUnit
            && now.getMinute() % interval == 0)
    {
        this.camService.writeSnapshot(webcam.getImage());
    }

    if (TimeUnit.HOURS == timeUnit
            && now.getHour() % interval == 0)
    {
        this.camService.writeSnapshot(webcam.getImage());
    }
}
0
mmamane