Bianca
Bianca

Reputation: 829

Run multiple instances of the SAME cron job in Spring

I want to be able to run the SAME scheduled job in Spring. After searching on the Internet, I figured out how to run multiple different jobs at the same time.

I have a @Service annotated class which has only one method, annotated with @Scheduled. I want to have multiple instances of this job running at the same time.

I am not using Quartz or Spring Batch( I have seen a lot of examples with Spring Batch).

The documentation doesn't clearly say if this can be achieved.

Upvotes: 3

Views: 3503

Answers (1)

G. Demecki
G. Demecki

Reputation: 10596

Yes, it can be easily achieved, but not with @Scheduled annotation. How? Let me first explain how Spring works.

Spring from every method annotated with @Scheduled creates a new Runnable object and then schedules it for execution to the TaskScheduler (ThreadPoolTaskScheduler to be precise). To see the exact code look at ScheduledAnnotationBeanPostProcessor.processScheduled().

So to fulfill your requirement: have multiple instances of the same job, but without using Quartz or Spring Batch we need to abandon @Scheduled annotation and do something a bit different than what the ScheduledAnnotationBeanPostProcessor does by default.

@Configuration
public class SpringConfig  {

  @Autowired
  private TaskScheduler scheduler;

  @Autowired
  private YourServiceAnnotatedClass service;

  @PostConstruct
  public void startJobs() {
    int numOfJobInstances = 3;
    List<ImportantJob> jobs = IntStream.range(0, numOfJobInstances)
        .mapToObj(i -> new ImportantJob("job" + i, service))
        .collect(Collectors.toList());

    jobs.forEach(this::schedule);
  }

  private void schedule(ImportantJob job) {
    scheduler.schedule(job, new CronTrigger("*/5 * * * * *"));
    // Above CronTrigger with 5 seconds was used, but feel free to use other variants, e.g.
    // scheduler.scheduleAtFixedRate()
    // scheduler.scheduleWithFixedDelay()
  }

  @Bean(destroyMethod = "shutdown")
  public TaskScheduler taskScheduler() {
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    taskScheduler.setPoolSize(3); // Adjust it to your needs
    return taskScheduler;
  }
}

class ImportantJob implements Runnable {
  private final String name;
  private final YourServiceAnnotatedClass service;

  public ImportantJob(String name, YourServiceAnnotatedClass service) {
    this.name = name;
    this.service = service;
  }

  @Override
  public void run() {
    service.doSth();
  }
}

As you can see, although @Scheduled is useful and simple, it is not very flexible. But with some effort you can gain much more control over scheduled tasks.

Upvotes: 0

Related Questions