44 votes

Comment arrêter une tâche planifiée qui a été démarrée à l'aide de l'annotation @Scheduled?

J'ai créé un simple tâche planifiée à l'aide de Spring Framework @Scheduled d'annotation.

 @Scheduled(fixedRate = 2000)
 public void doSomething() {}

Maintenant, je veux arrêter cette tâche, il n'a plus besoin.

Je sais qu'il pourrait être une alternative pour vérifier un conditionnel drapeau au début de cette méthode, mais ce ne sera pas arrêter l'exécution de cette méthode.

Est-il rien de Printemps pour arrêter l' @Scheduled de la tâche ?

23voto

Mahesh Points 604

Option 1: à l'Aide d'un post-processeur

Approvisionnement en ScheduledAnnotationBeanPostProcessor et invoquer explicitement postProcessBeforeDestruction(Object bean, String beanName), pour le haricot dont la planification doit être arrêté.


Option 2: le Maintien d'une carte de cible de haricots à son Avenir

private final Map<Object, ScheduledFuture<?>> scheduledTasks =
        new IdentityHashMap<>();

@Scheduled(fixedRate = 2000)
public void fixedRateJob() {
    System.out.println("Something to be done every 2 secs");
}

@Bean
public TaskScheduler poolScheduler() {
    return new CustomTaskScheduler();
}

class CustomTaskScheduler extends ThreadPoolTaskScheduler {

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
        ScheduledFuture<?> future = super.scheduleAtFixedRate(task, period);

        ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task;
        scheduledTasks.put(runnable.getTarget(), future);

        return future;
    }

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
        ScheduledFuture<?> future = super.scheduleAtFixedRate(task, startTime, period);

        ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task;
        scheduledTasks.put(runnable.getTarget(), future);

        return future;
    }
}

Lors de la planification d'un bean doit être interrompu, vous pouvez chercher la carte correspondant à l' Future et explicitement l'annuler.

14voto

TinyOS Points 1081

Voici un exemple où nous pouvons arrêter, démarrer et répertorier également toutes les tâches planifiées en cours d'exécution:

 @RestController
@RequestMapping("/test")
public class TestController {

private static final String SCHEDULED_TASKS = "scheduledTasks";

@Autowired
private ScheduledAnnotationBeanPostProcessor postProcessor;

@Autowired
private ScheduledTasks scheduledTasks;

@Autowired
private ObjectMapper objectMapper;

@GetMapping(value = "/stopScheduler")
public String stopSchedule(){
    postProcessor.postProcessBeforeDestruction(scheduledTasks, SCHEDULED_TASKS);
    return "OK";
}

@GetMapping(value = "/startScheduler")
public String startSchedule(){
    postProcessor.postProcessAfterInitialization(scheduledTasks, SCHEDULED_TASKS);
    return "OK";
}

@GetMapping(value = "/listScheduler")
public String listSchedules() throws JsonProcessingException{
    Set<ScheduledTask> setTasks = postProcessor.getScheduledTasks();
    if(!setTasks.isEmpty()){
        return objectMapper.writeValueAsString(setTasks);
    }else{
        return "No running tasks !";
    }
}
 

}

7voto

Jairton Junior Points 380

Il y a quelque temps, j'avais dans mon projet cette exigence que tout composant devrait pouvoir créer une nouvelle tâche planifiée ou arrêter le planificateur (toutes les tâches). J'ai donc fait quelque chose comme ça

 @Configuration
@EnableScheduling
@ComponentScan
@Component
public class CentralScheduler {

    private static AnnotationConfigApplicationContext CONTEXT = null;

    @Autowired
    private ThreadPoolTaskScheduler scheduler;

    public static CentralScheduler getInstance() {
        if (!isValidBean()) {
            CONTEXT = new AnnotationConfigApplicationContext(CentralScheduler.class);
        }

        return CONTEXT.getBean(CentralScheduler.class);
    }

    @Bean
    public ThreadPoolTaskScheduler taskScheduler() {
        return new ThreadPoolTaskScheduler();
    }

    public void start(Runnable task, String scheduleExpression) throws Exception {
        scheduler.schedule(task, new CronTrigger(scheduleExpression));
    }

    public void start(Runnable task, Long delay) throws Exception {
        scheduler.scheduleWithFixedDelay(task, delay);
    }

    public void stopAll() {
        scheduler.shutdown();
        CONTEXT.close();
    }

    private static boolean isValidBean() {
        if (CONTEXT == null || !CONTEXT.isActive()) {
            return false;
        }

        try {
            CONTEXT.getBean(CentralScheduler.class);
        } catch (NoSuchBeanDefinitionException ex) {
            return false;
        }

        return true;
    }
}
 

Je peux donc faire des choses comme

 Runnable task = new MyTask();
CentralScheduler.getInstance().start(task, 30_000L);
CentralScheduler.getInstance().stopAll();
 

Gardez à l'esprit que, pour certaines raisons, je l'ai fait sans me soucier de la concurrence. Sinon, il devrait y avoir une synchronisation.

5voto

so-random-dude Points 5411

Il y a un peu d'ambiguïté dans cette question

  1. Quand vous dites "stop à cette tâche", avez-vous l'intention d'arrêter de telle manière qu'il récupérables (si oui, par programmation, à l'aide d'une condition qui se pose avec la même application? externe ou de l'état?)
  2. Êtes-vous en cours d'exécution d'autres tâches dans le même contexte? (Possibilité de la fermeture de l'ensemble de l'application plutôt que d'une tâche) -- Vous pouvez faire usage de l'actionneur.l'arrêt d'extrémité dans ce scénario

Ma meilleure supposition est, vous êtes à la recherche pour l'arrêt d'une tâche à l'aide d'une condition qui pourrait survenir dans la même application, dans un recouvrable de la mode. Je vais essayer de répondre en fonction de cette hypothèse.

C'est le plus simple possible solution que je pense, mais je vais faire quelques améliorations comme le début du retour, plutôt que si imbriquéess

@Component
public class SomeScheduledJob implements Job {

    private static final Logger LOGGER = LoggerFactory.getLogger(SomeScheduledJob.class);

    @Value("${jobs.mediafiles.imagesPurgeJob.enable}")
    private boolean imagesPurgeJobEnable;

    @Override
    @Scheduled(cron = "${jobs.mediafiles.imagesPurgeJob.schedule}")
    public void execute() {

        if(!imagesPurgeJobEnable){
            return;
        }
        Do your conditional job here...
   }

Propriétés pour le code ci-dessus

jobs.mediafiles.imagesPurgeJob.enable=true or false
jobs.mediafiles.imagesPurgeJob.schedule=0 0 0/12 * * ?

2voto

Tony Points 3371

Prévue

Quand le printemps processus d' Scheduled, il va parcourir chaque méthode annotée cette annotation et à organiser les tâches par les fèves de la source suivante montre:

private final Map<Object, Set<ScheduledTask>> scheduledTasks =
        new IdentityHashMap<Object, Set<ScheduledTask>>(16);

Annuler

Si vous voulez juste pour annuler l'une répétition de la tâche planifiée, vous pouvez faire comme suit (ici est un exécutable démo dans mon repo):

@Autowired
private ScheduledAnnotationBeanPostProcessor postProcessor;
@Autowired
private TestSchedule testSchedule;

public void later() {
    postProcessor.postProcessBeforeDestruction(test, "testSchedule");
}

Avis

Il va trouver le les haricots de l' ScheduledTask et annuler un par un. Ce qui doit être remarqué, c'est qu'il sera également l'arrêt de la cours d'exécution de la méthode (en tant que postProcessBeforeDestruction source montre).

    synchronized (this.scheduledTasks) {
        tasks = this.scheduledTasks.remove(bean); // remove from future running
    }
    if (tasks != null) {
        for (ScheduledTask task : tasks) {
            task.cancel(); // cancel current running method
        }
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X