I use
CommandLineJobRunnerWrapper
as main class. For run job use
SimpleJobLauncher
for execute job one time. How I could schedule it to execute e.g. each day at 10 o'clock?
Because now application immedeately exit after method execute finished.
I have tried use spring scheduler but without success.
You could just use the Scheduled annotation
#Scheduled(cron="0 0 10 * * MON-FRI")
on your method.
Related
I have a project which executes multiple scheduled method at start up.
I remarked that after scheduled methods are executed, the opened threads do not close, but remain in a 'parking' state.
Is this a normal behavior ?
Aren't the threads suppose to close after method is executed ? (Because keeping multiple threads open just slows down the application and consumes more RAM.)
Here are my code configurations:
#EnableScheduling
#Configuration
#ConditionalOnProperty(name = "scheduling.enabled", matchIfMissing = true)
public class SchedulingConfiguration implements SchedulingConfigurer {
}
Here is an example of method called in service:
#Scheduled(cron = "0 0 4 * * *")
protected void updateExchangeRates() {
if (enablePostConstruct) {
countryService.updateCountryExchangeRates();
}
}
I would like to run the scheduled methods asynchronously, with a max thread pool consumed between 10-15 threads. And after execution, the thread to close and reopen in case it got to the point when it needs to be executed again.
Can you guide me please how this can be achieved ?
I tried to implement SchedulingConfigurer and perform executorService.shutdown(), but it did not work.
You could use a method annotated with #PreDestroy to invoke executorService.shutdown(). I wouldn't bother about the Parking State, you probably want those threads to be ready for the next invocation, so not really harmful that they are parked.
Nothing wrong with the code.
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.
I'm using Spring Batch with Spring cloud tasks. I have the following configuration in my job:
#Bean
public Job jobDemo(
#Value("${jobname}")String jobName,
JobBuilderFactory jobBuilderFactory,
JobCompletionNotificationListener listener
) {
return jobBuilderFactory.get(jobName)
.incrementer(new RunIdIncrementer())
.preventRestart()
.listener(listener)
.flow(stepA())
.end()
.build();
}
I don't want the restart functionality in the job, that's why I have put .preventRestart(). I want to launch a new job every time the task runs, that is, a new instance of the job to run even when the last time the job has failed or stopped or anything. But I'm getting the following error:
org.springframework.batch.core.repository.JobRestartException: JobInstance already exists and is not restartable
This happens only in the scenarios when the job does not finish sucessfully. Any ideas about the solution?
A JobInstance can only be completed once successfully. When you are starting a Spring Batch job via Spring Boot, Spring Batch handles the logic to increment a JobParameter if there is a JobParametersIncrementer provides (as you have). However...when Spring Batch does that incrementing, it only increments if the previous job was successful. In your case, you want it to always increment. Because of that, you're going to need to write your own CommandLineRunner that always increments the JobParameters.
Spring Boot's JobLauncherCommandLineRunner is where the code to launch a job exists. You'll probably want to extend that and override it's execute method to be sure job parameters are always incremented.
How can I run a job configured using Spring-Batch right after application startup?
Currently I'm specifying an exact time using cron job, but that requires to change the cron every time I restart the application:
#JobRegistry, #Joblauncher and a Job.
I execute the job as follows:
#Scheduled(cron = "${my.cron}")
public void launch() {
launcher.run(job, params);
}
Checking aroud Spring code I have found SmartLifecycle
An extension of the Lifecycle interface for those objects that require
to be started upon ApplicationContext refresh and/or shutdown in a
particular order. The isAutoStartup() return value indicates whether
this object should be started at the time of a context refresh.
Try creating a custom bean implementing SmartLifecycle and setting autoStartup; when this custom bean start method is invoked launch your job.
A few options that I can think of on the places to put your startup logic:
.1. In a bean #PostConstruct annotated method, reference is here - http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-postconstruct-and-predestroy-annotations
.2. By implementing an ApplicationListener, specifically for either ContextStartedEvent or ContextRefreshedEvent. Reference here - http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#context-functionality-events
In my web-app (Tomcat 6) I define a Quartz Scheduler in a class extending HttpServlet: this class is called to init.
The scheduler runs immediately and it has an interval of 1 minute, but after the first step it's not running.
When I change the parameter of scheduler by webpage, the scheduler is running correctly with the same code.
This is the code:
JobDetail job = newJob(ClassOfTask.class).withIdentity(NAME_JOB_MAIL, NAME_JOB_THREAD).build();
//various code
String cronExpression = buildCronExpression();
Trigger trigger = newTrigger().withIdentity(NAME_TRIGGER).startAt(startJob).endAt(endJob).forJob(job.getKey()).withSchedule(cronSchedule(cronExpression)).build();
scheduler.addJob(jobDetail, true);
scheduler.scheduleJob(trigger);
I tried to insert
scheduler.start();
but the problem remains.
When I modify the scheduled task in web page, I use this method
scheduler.rescheduleJob(oldTrigger.getKey(), trigger);
and in this case it works.
What's it the problem?