Spring Scheduler stops working for my cron expression - spring

I've a method scheduled to run periodically with Spring Scheduler, it's been working fine and stopped working today with no error. What could be the potential cause ? Is there any alternative way to schedule task periodically using Spring Scheduler that ensures that the method will be executed no matter what?
#Scheduled(cron="0 0/1 * * * ?")
public void executePollingFlows(){
if(applicationConfig.isScheduleEnabled()) {
for (long flowId : applicationConfig.getPollingFlowIds()) {
flowService.executeFlow(flowId);
}
logger.info("Finished executing all polling flows at {}", new Date());
}
}

You may have got Out of Memory exception if the job could not finish its tasks but you try to run it again and again. If it is a Out of Memory exception you may try to create a ThreadPool and check it in every run. If there is no enough space in the ThreadPool you can skip the task for this turn.
There is alternative way to use #Scheduled periodically. You may change your #Scheduled annotation with this:
#Scheduled(fixedRate=1000)
It will still be running in every second and if necessary you can add initialDelay to it:
#Scheduled(initialDelay=1000, fixedRate=1000)
You can find more details about fixedRate, initialDelay and fixedDelay here:
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html

Related

how to prevent quartz from running another job if the previous one is still running?

I'm using Quarkus. My Quartz jobs are scheduled to run every 10 seconds:
return TriggerBuilder.newTrigger()
.withIdentity("my-job")
.startNow()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.repeatForever()
).build();
This works fine but jobs keep triggering every 10 seconds irrespective of whether or not the last one finishes. I need the next job to start only if there are no jobs currently running job. How do I accomplish this?
Add #DisallowConcurrentExecution on you Job class.
as example :
#DisallowConcurrentExecution
public class MyScheduledJob implements Job {
//execution method
}

How to schedule #RabbitListener

As per the requirement, I don't want to consume message from queue for a couple of hours in a day.
/*Consume time from 9AM to 5PM*/
#Scheduled(cron = "* * 9-16 * * *")
#RabbitListener(queues = "${QUEUE_NAME}")
public void processMessage(SomeMessage message) {
}
I see a few options
Keep your application started just when consumption is required
The application could be started by cron (or other schedulers) and once started, schedule itself to stop after some time.
Consume messages in an imperative, not declarative way.
Just use https://docs.spring.io/spring-amqp/docs/2.1.4.RELEASE/reference/#polling-consumer
Use
org.springframework.amqp.coreAmqpTemplate#receive method in a loop. Make sure that your loop is running only during scheduled hours.
Use Delayed Messages
https://www.cloudamqp.com/docs/delayed-messages.html
This requires changes in the producer. The consumer could be running all the time. But if during sending the message you delay it, so it will be delivered according to your schedule.

How to manage logs of two seperate cron in a single project in java

There is an issue in running Multiple Cron in Spring. I have created multi module maven project in which there are two separate cron running but at some point of time they coincide and it becomes very tedious to debug from the log.
Is there any way of having a separate log or some way when one cron is running then another should not start, I mean at one point of time only one cron should run.
#Scheduled(cron="0 0 */2 * * *")
public void startAnalysis() {
logger.info("Inside of Analysis scheduler");
// Doing Something
}
#Scheduled(cron="0 0 */6 * * *")
public void startAnalysis() {
logger.info("Inside of Analysis1 scheduler");
// Doing Something
}
Above are the two crons that I am running. Currently, I am using sl4j for logging purpose.
You can create two instances of the logger, each with a different name and configure them to log to different files in your logging framework.
Spring by default uses a single threaded Executor. so no two
#Scheduled tasks will be execute simultaneously. even if there are two
#Scheduled methods in completely unrelated classes will not overlap
and that is because there is only a single thread to execute tasks.
the only possiblity for task to be executed at the same time is to have multi thread executors which defined as:
#EnableScheduling
#Configuration
public class MyConfiguration implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar
scheduledTaskRegistrar) {
scheduledTaskRegistrar.setScheduler(taskExecutor());
}
#Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(5);
}
}
If you have such custom configuration that defines a thread pool for schedule tasks, you should remove it.
Please use Log4J programmatic config, you can separate different log file.
https://www.codejava.net/coding/how-to-configure-log4j-as-logging-mechanism-in-java?showall=&start=2#ProgrammaticConfiguration

What is the best way to run a scheduled batch with spring boot

This is the first time I will work with Spring batch, and I got a task to do where I have to run a planned task every night at 00:00, which will truncate a table in the database, and re-fill it.
I don't know what is the best way to do this, I read a tutorial about Scheduling Tasks where I created a scheduled function and in this function I'll write the code which will execute my SQL scripts, as following :
#Component
public class ScheduledTasks {
#Scheduled(fixedRate = 5000)
public void reportCurrentTime(){
//My code goes here
}
}
But I don't know is this the best way to do it, since I found in some tutorials that they are working with JobLauncher and something called job-report.xml.
Any advices how to get this done ?
Use
#Scheduled(cron="0 0 0 * * *")
Look at https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
Don't forget to add #EnableScheduling to your configuration.

Limit the lifetime of a batch job

Is there a way to limit the lifetime of a running spring-batch job to e.g. 23 hours?
We start a batch job daily by a cron job and he job takes about 9 hours. It happened under some circumstances that the DB connection was so slow that the job took over 60 hours to complete. The problem is that the next job instance gets started by the cronjob the next day - and then anotherone the day after - and anotherone...
If this job is not finished within e.g. 23 hours, I want to terminate it and return an error. Is there a way to do that out-of-the-box with spring-batch?
Using a StepListener you can stop a job by calling StepExecution#setTerminateOnly.
stepBuilderFactory
...
.writer(writer)
.listener(timeoutListener)
...
.build()
And the TimeoutListener could look like this
#Component
public class TimeoutListener implements StepListener {
private StepExecution stepExecution;
#BeforeStep
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
#BeforeRead
public void beforeRead() {
if (jobShouldStop()) {
stepExecution.setTerminateOnly();
}
}
private boolean jobShouldStop() {
// ...
}
}
This will gracefully stop the job, without forcefully terminate any running steps.
Spring Batch specifically avoids the issue of job orchestration which this falls into. That being said, you could add a listener to your job that checks for other instances running and calls stop on them before beginning that one. Not knowing what each job does, I'm not sure how effective that would be, but it should be a start.
If you write your own job class to launch the process you can make your class implement StatefulJob interface, which prevents concurrent launches of the same job. Apart from that you can write your own monitoring and stop the job programatically after some period, but it will require some custom coding, I dont know if there is anything build-in for such use case.

Resources