I have a Spring boot 2.1.6.RELEASE application in which I have a method annotated with
#Scheduled(cron = "*/10 * * * * *}
I want it to run with that cron, EVEN IF another execution is already in progress.
I tried increasing the executor thread number using the application.properties file:
spring.task.scheduling.pool.size=10
But it didn't seem to work as it is still waiting for an execution to finish before starting the next one.
What is the proper way to do parallel executions using a cron in the #Scheduled annotation?
It is true that the default pool size for the task scheduler is 1 but increasing this pool size is only making more threads available for other #Scheduled methods. The intended behaviour is not for methods to run in parallel as otherwise threads could become exhausted.
If you wish to change this behaviour to allow the same method to run in parallel you need to use #EnableAsync and #Async annotations. You might also want to change the pool size of the task executor. That being said, keep in mind that you may still exhaust your threads so be very careful with changing this intended behaviour.
Related
I am currently reviewing options to develop looped method execution and one suggestion was to make use of simple Spring #Scheduled annotation. So if I use this approach and use #Scheduled(fixedRate = 1000) in which task scheduled to run each second, If in case each task execution is taking more than second and if there is a huge backlog of scheduled tasks in millions, can it cause some sort of leak?
I have several tasks #Scheduled with fixedDelay. Thread pool size in application.properties is sufficiently larger than the number of these tasks. One of the tasks routinely stops doing anything as seen from the lack of activity in the log files from that task. There is no uncaught exception and even if there were ,the next invocation of the schedule should not be affected. The task does IO operations (network calls). What could possibly cause this?
I am trying to schedule something than need to be ran every 200ms:
#Scheduled(every = "0.2s")
What's the recommended way to do it?
Is there a good reason why #Scheduled doesn't support rate under the second?
Unfortunately, this is not supported. The idea is that #Scheduled is only used for cron-like tasks with an accuracy of seconds (note that the Cron standard is designed to work with an accuracy of minutes).
However, you can inject a managed Vertx instance and make use of Vertx.setPeriodic(). But keep in mind that the handler is executed on an event loop thread and so the code should not block. If you really need to execute some blocking code then look at Vertx.executeBlocking().
The plan is to add an injectable managed ScheduledExecutorService for similar use cases.
According to the business logic of my Spring Boot application with Quartz Scheduling and MongoDB as Job persistent storage, every user of the system can create the postponed job that must be executed at some point in time. The user chooses the time when it must be executed.
Right now I'm thinking about the approach where every user will create a dedicated JobDetail for every postponed job, something like this:
schedulerFactoryBean.getScheduler().addJob(jobDetail(), true, true);
The issue I can potentially see here, that with this approach I can quickly create thousands of jobs in Quartz scheduler. Previously I never scheduled such amount of jobs in Spring Scheduling with Quartz and don't know how the system will handle it. Is it a good idea to implement the system in such way and will Spring Scheduling Quartz handle such amount of jobs without problems?
Yes, Quartz itself can handle thousands of jobs and triggers without any issues.
If you are going to have many jobs executing concurrently, just make sure that you configure Quartz with a sufficient number of worker threads. The number of worker threads should be typically equal to the maximum number of jobs that can be running concurrently + some small buffer (10% or so) just in case.
From what you write I assume that your jobs will be one-off jobs, i.e. each job will be executed only once. If that is the case, Quartz can automatically discard your jobs as soon as they finish executing unless your jobs are marked as durable. Quartz automatically removes non-durable jobs if they are not scheduled to run in the future. This feature may help you reduce the total number of registered jobs.
I hope this helps. If not, please ask.
In my Spring Boot application, based on the Cron job(runs every 5 minutes) I need to process 2000 products in my database.
Right now the process time of these 2000 products takes more than 5 minutes. I ran into the issue where the second Cron job runs when the first one is not completed yet.
Is there in Spring/Cron out of the box functionality that will allow to synchronize these jobs and wait for the previous job completion before starting the next one?
Please advise how to properly implement such kind of system. Anyway, the following technologies are also available Neo4j, MongoDB, Kafka. Please advise how to properly design/implement this functionality using the Spring/Cron separately or even together with the mentioned technologies.
1) You may try to use #Scheduled(fixedDelay = 5*60*1000). It will guarantee that next invocation will happen strictly in 5 minutes after previous one is finished. But this may break your scheduling requirements
2) You can limit the underlying ThreadExecutor's pool size to 1 thread, so next invocation will have to wait until previous is finished, but this, again, can break the logic, since it would affect all periodic tasks invoked by #Scheduled
3) You can use Quartz instead of spring's native #Scheduled. It's more complicated to configure, but allows to achieve the desired behaviour via #DisallowConcurrentExecution annotation or via setting JobDetail::isConcurrentExectionDisallowed in your job details