0

I create schedule task without @scheduled annotation instead using taskregistrar (as I get more flexibility in cancelling, dynamically changing the delay etc - please don't focus on why I use taskregistrar). But then I noticed that TaskScheduler has no effect while doing so. Code is given below

    //in my SchedulingConfigurer
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setThreadNamePrefix("proc-task-pool-");
        scheduler.setPoolSize(10);//No use - always use 8
        scheduler.initialize();
        taskRegistrar.setTaskScheduler(scheduler);//commenting this line also result in same behavior
        taskRegistrar.scheduleFixedRateTask(new FixedRateTask(myService::processData,
                1000L,
                0L));
    }
    //in my service class 
    @Async
    public void processData() {
        log.info("inside processData {} {}", Thread.currentThread().getName(), LocalDateTime.now());
        try {
            Thread.sleep(20000L);
        } catch (InterruptedException e) {
            log.error("InterruptedException ");
        }
    }

Whether I set a custom scheduler or not, I noticed that my fixedRateTask is always processed by 8 threads. Below is the console log

inside processData task-1 2020-05-12T10:33:31.762
inside processData task-2 2020-05-12T10:33:32.743
inside processData task-3 2020-05-12T10:33:33.747
inside processData task-4 2020-05-12T10:33:34.742
inside processData task-5 2020-05-12T10:33:35.742
inside processData task-6 2020-05-12T10:33:36.739
inside processData task-7 2020-05-12T10:33:37.742
inside processData task-8 2020-05-12T10:33:38.743
inside processData task-1 2020-05-12T10:33:51.762
inside processData task-2 2020-05-12T10:33:52.744
inside processData task-3 2020-05-12T10:33:53.747
inside processData task-4 2020-05-12T10:33:54.743
inside processData task-5 2020-05-12T10:33:55.743

What went wrong?

EDIT

m-deinum's comment below helped me to resolve the problem.

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

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        this.scheduledTask = taskRegistrar.scheduleFixedRateTask(new FixedRateTask(myService::processData,
                configParams.getFixedratedelay(),
                0L));
    }

EDIT 2

m-deinum's another comment helped me to optimize. I removed the TaskExecutor bean altogether and used the following configuration property.

spring.task.execution.pool.core-size=20=100  //I wrongly used scheduling.pool.size earlier
Winster
  • 943
  • 10
  • 28
  • 1
    You need a `TaskExecutor` not a `TaskScheduler`. You have async as well so it will be executd by a taskexecutor not the taskschedulr. EIther remove the async or configure a taskexecutor properly. – M. Deinum May 12 '20 at 07:50
  • Removing async annotation will end up running the task every 20seconds. – Winster May 12 '20 at 08:10
  • On debug, it shows ThreadPoolTaskScheduler internally uses ScheduledExecutorService with corePoolSize = 20 maximumPoolSize = 2147483647 – Winster May 12 '20 at 08:17
  • @M.Deinum, you are right. Using taskExecutor explicitly defined as a bean helped! Thank you! – Winster May 12 '20 at 08:26
  • 1
    If you have a recent Spring Boot version you don't need a `TaskExecutor` you can just specify the number of threads in configuration. Also you don't need the `TaskScheduler` as well. If you want to execute tasks each time regardless if another one is running you might be better of using a cron expression, which would utilize your `TaskScheduler` (which you should define as an `@Bean` when used). – M. Deinum May 12 '20 at 08:42
  • Thanks @M.Deinum. I removed the taskexecutor and just used `spring.task.scheduling.pool.size=50`. Thanks for the advice on cron expr. – Winster May 12 '20 at 08:57
  • 1
    You removed the executor and configured the scheduling? You should be setting `spring.task.execution.pool.core-size`. Also you are making things overly complex with that dynamic binding as that is already supported out-of-the-box with the `@RefreshScope`. Looks like you are trying to reinvent the wheel. – M. Deinum May 12 '20 at 09:00
  • Thanks for the correction. With refreshscope, I could not change the interval defined in Scheduled annotation. But I ended up in another problem as listed here https://stackoverflow.com/questions/61747502/how-to-stop-a-fixedratescheduledtask-in-spring-without-interrupting-a-running-th – Winster May 12 '20 at 09:11
  • Yes you can, if you make the bean refreshscoped and use the proper arguments (`fixedRateString` instead of `fixedRate` and let it point to the property instead of the direct value!). – M. Deinum May 12 '20 at 09:12
  • I get same problem mentioned in https://stackoverflow.com/questions/50440468/refreshscope-stops-scheduled-task – Winster May 12 '20 at 09:25
  • 1
    ah that issue. Point is that those `@Scheduled` annotations are processed by the `ScheduledAnnotationBeanPostProcessor`. You could add an `ApplicationListener` for the specific refresh event, which triggers that postprocessor again. I would also suggest to register an issue with Spring Cloud as I would expect the refreshing to also re-register scheduled tasks. – M. Deinum May 12 '20 at 09:33
  • Great. It works. Much simpler now. I also verified that upon refresh, previous threads gracefully finish – Winster May 12 '20 at 09:50
  • @M.Deinum, when opentracing is added to the classpath, current ScheduledTask is not cancelled upon refresh. A sample application is here github.com/winster/SpringSchedulerDynamic What do you think? – Winster Jul 14 '20 at 13:06

0 Answers0