I have followed very simple examples online to set up a cron job in Spring yet I keep getting this error in my Tomcat startup log each and every time:
2015-05-25 00:32:58 DEBUG ScheduledAnnotationBeanPostProcessor:191 - Could not find default TaskScheduler bean org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.scheduling.TaskScheduler] is defined 2015-05-25 00:32:58 DEBUG ScheduledAnnotationBeanPostProcessor:202 - Could not find default ScheduledExecutorService bean org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.scheduling.TaskScheduler] is defined
And the 2 java classes used to implement the cron:
The @Configuration class:
@Configuration @EnableScheduling public class ClearTokenStoreCronEnable { final static Logger log = LoggerFactory.getLogger(ClearTokenStoreCronEnable.class); private @Autowired TokenStoreRepository tokenStoreRepository; }
and Cron job class:
@Service public class ClearTokenStoreWorkerService { final static Logger log = LoggerFactory.getLogger(ClearTokenStoreWorkerService.class); private @Autowired TokenStoreRepository tokenStoreRepository; //@Scheduled(fixedDelay=5000) //run daily at midnight @Scheduled(cron = "0 0 * * * *") public void tokenStoreTable() { log.debug("tokenstore table truncated - start"); tokenStoreRepository.deleteAll(); log.debug("tokenstore table truncated - end"); } }
As a side note, the cron job runs at midnight but it also seems to run randomly at other times. Not sure if this is a bug or my cron expression is wrong: @Scheduled(cron = "0 0 * * * *")
My main concern at this time is why am I getting ScheduledAnnotationBeanPostProcessor
errors? It's looking for a TaskScheduler and ScheduledExectorService. I just need to fire this once a day. I am not doing any concurrent processing or where I need multiple threads. Ultimately are these errors harmful OR do I need to fix them?
There is no need to use @Async. Just use fixedRate attribute of @Scheduled instead of fixedDelay. Spring will make another invocation on the method after the given time regardless of any call is already being processed.
Another way to stop the scheduler would be manually canceling its Future. In the cases with multiple scheduler tasks, then we can maintain the Future map inside of the custom scheduler pool but cancel the corresponding scheduled Future based on scheduler class.
The cancel() method is used to cancel the timer task. The cancel() methods returns true when the task is scheduled for one-time execution and has not executed until now and returns false when the task was scheduled for one-time execution and has been executed already.
The schedulers do not start or stop. In the real world, it is necessary to stop and restart the scheduler without restarting the spring boot application. The ScheduledAnnotationBeanPostProcessor class allows you to programmatically start and stop the scheduler without having to restart the spring boot application.
according to exception Info Could not find default TaskScheduler bean
, the config should define TaskScheduler
rather than "Executor"
@Configuration public class AppContext extends WebMvcConfigurationSupport { @Bean public TaskScheduler taskScheduler() { return new ConcurrentTaskScheduler(); } // Of course , you can define the Executor too @Bean public Executor taskExecutor() { return new SimpleAsyncTaskExecutor(); } }
EDIT: the best answer is here and it involves creating an Executor:
@Configuration @EnableAsync public class AppContext extends WebMvcConfigurationSupport { @Bean public Executor taskExecutor() { return new SimpleAsyncTaskExecutor(); } }
PREVIOUS (still valid though):
The NoSuchBeanDefinitionException is logged with a DEBUG severity and can be safely ignored. If you look at the source code for ScheduledAnnotationBeanPostProcessor, you see that it first tries to get a TaskScheduler, then a ScheduledExecutorService, then it keeps going on "falling back to default scheduler":
if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) { Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type"); try { // Search for TaskScheduler bean... this.registrar.setScheduler(this.beanFactory.getBean(TaskScheduler.class)); } catch (NoUniqueBeanDefinitionException ex) { throw new IllegalStateException("More than one TaskScheduler exists within the context. " + "Remove all but one of the beans; or implement the SchedulingConfigurer interface and call " + "ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback.", ex); } catch (NoSuchBeanDefinitionException ex) { logger.debug("Could not find default TaskScheduler bean", ex); // Search for ScheduledExecutorService bean next... try { this.registrar.setScheduler(this.beanFactory.getBean(ScheduledExecutorService.class)); } catch (NoUniqueBeanDefinitionException ex2) { throw new IllegalStateException("More than one ScheduledExecutorService exists within the context. " + "Remove all but one of the beans; or implement the SchedulingConfigurer interface and call " + "ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback.", ex); } catch (NoSuchBeanDefinitionException ex2) { logger.debug("Could not find default ScheduledExecutorService bean", ex); // Giving up -> falling back to default scheduler within the registrar... } } }
You can remove the exception by setting at least a INFO severity on org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor, like
<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
when using logback.
The cron expression has six fields:
second (0-59), minute (0-59), hour (0-23, 0 = midnight), day (1-31), month (1-12), weekday (1-7, 1 = Sunday)
The syntax can be found in the quartz docs. I'm not sure about the "?" character because, although the page says
The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify “no specific value”. This is useful when you need to specify something in one of the two fields, but not the other.
the examples on that page actually use ? even when the other field is *. IMHO all should work with just *, so in order to execute every midnight, the expression should be
0 0 0 * * *
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With