web-dev-qa-db-fra.com

Comment changer le @Scheduled fixedDelay de Spring à l'exécution

J'ai besoin d'exécuter un travail par lots à un intervalle fixe et j'ai la possibilité de modifier l'heure de ce travail par lots au moment de l'exécution. Pour cela, je suis tombé sur une annotation @Scheduled fournie dans le cadre de Spring. Mais je ne sais pas comment je changerais la valeur de fixedDelay lors de l'exécution. J'ai fait quelques recherches sur Google, mais je n'ai rien trouvé d'utile.

26
jsf

Vous pouvez utiliser un Trigger pour définir dynamiquement la prochaine heure d'exécution. Voir ma réponse ici:

Planification d'un travail avec Spring par programmation (avec fixedRate défini dynamiquement)

24
ach

Dans Spring Boot, vous pouvez utiliser directement une propriété d'application!

Par exemple:

@Scheduled(fixedDelayString = "${my.property.fixed.delay.seconds}000")
private void process() {
    // your impl here
}

Notez que vous pouvez également avoir une valeur par défaut dans le cas où la propriété n'est pas définie, par exemple pour avoir une valeur par défaut de "60" (secondes):

@Scheduled(fixedDelayString = "${my.property.fixed.delay.seconds:60}000")

D'autres choses que j'ai découvertes:

  • la méthode doit être nulle
  • la méthode ne doit pas avoir de paramètres
  • la méthode peut être private

J'ai trouvé pouvoir utiliser private visibilité à portée de main et l'ai utilisé de cette façon:

@Service
public class MyService {
    public void process() {
        // do something
    }

    @Scheduled(fixedDelayString = "${my.poll.fixed.delay.seconds}000")
    private void autoProcess() {
        process();
    }
}

Étant private, la méthode planifiée peut être locale à votre service et ne pas faire partie de l'API de votre service.

En outre, cette approche permet à la méthode process() de renvoyer une valeur, contrairement à une méthode @Scheduled. Par exemple, votre méthode process() peut ressembler à:

public ProcessResult process() {
    // do something and collect information about what was done
    return processResult; 
}

pour fournir des informations sur ce qui s'est passé pendant le traitement.

48
Bohemian

créer une interface, quelque chose comme ça:

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

Ensuite, permet d'implémenter l'interface de déclenchement qui se trouve à org.springframework.scheduling dans le projet Spring-context.

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

maintenant configuration:

@Configuration
public class DynamicSchedulerConfig {
    @Bean
    public CustomDynamicSchedule getDynamicScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.initialize();
        return  new CustomDynamicSchedule(threadPoolTaskScheduler);
    }
}

et utilisation:

@EnableScheduling
@Component
public class TestSchedulerComponent {

    @Autowired
    private CustomDynamicSchedule dynamicSchedule;

    @Scheduled(fixedDelay = 5000)
    public void testMethod() {
        dynamicSchedule.delay(1000l);
        dynamicSchedule.increaseDelayInterval(9000l);
        dynamicSchedule.decreaseDelayInterval(5000l);
    }

}
7
grep

AFAIK, l'API Spring ne vous permettra pas d'accéder aux éléments internes dont vous avez besoin pour modifier le déclencheur. Mais vous pouvez plutôt configurer manuellement les beans:

<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
    <property name="jobDetail" ref="jobDetail" />
    <property name="startDelay" value="10000" />
    <property name="repeatInterval" value="50000" />
</bean>

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="simpleTrigger" />
        </list>
    </property>
</bean>

Puis, comme indiqué dans SchedulerFactoryBean:

Pour un enregistrement dynamique des travaux lors de l'exécution, utilisez une référence de bean à ce SchedulerFactoryBean pour obtenir un accès direct au Quartz Scheduler (org.quartz.Scheduler). Cela vous permet de créer de nouveaux travaux et déclencheurs, ainsi que de contrôler et de surveiller l'intégralité du planificateur.

2
Víctor Romero