springs scheduing jobs for a given - spring

Spring MVC:
how to schedule jobs at a specific time in a day. schedule time differs every day. time when these jobs needs to be run are available in a database table. I was able to read the data from table but not sure how to schedule them in spring mvc. can someone help.

The Spring scheduler requires that you know the time of day at compile time so this is going to get a little weird. But if you want to be creative you can schedule a job at midnight to query the database for the exact time the task should run, sleep until that time, and then execute the task. Something like this:
public abstract class DailyTaskRunner {
// Execute the specific task here
protected abstract void executeTask();
// Query the database here
// Return the number of milliseconds from midnight til the task should start
protected abstract long getMillisTilTaskStart();
// Run at midnight every day
#Scheduled(cron="0 0 * * *")
public void scheduledTask() {
long sleepMillis = getMillisTilTaskStart();
try {
Thread.sleep(sleepMillis);
} catch(InterruptedException ex) {
// Handle error
}
executeTask();
}
}
You can extend this class once for every job.

Related

Spring synchronize saving to database with another instances

I have 2 instances of my Spring boot application, I am using spring JPA.
Cron scheduler run method every one hour which
first, check if record is already updated, if it's updated it should skip and don't update, but it's updated anyway on both instances.
How to implement, something like synchronized, allow to read only when something is done?
#Scheduled(cron = "0 0 * * * ?", zone = "Europe/Paris")
public void updateServers() {
applicationServerRepository.findAll().forEach(this::updateServerInfo);
}
Please explain the problem more detailed&exact.
But as I understand, you should:
Or run the cron jobs only in one instance. (Back in 90ies we did it "manually", but spring-boot-profiles offer here great opportunity: decorate "all #scheduled beans" (re-factoring!?) with #Profile("cronFooBar"), and activate/add it only on one instance.)
Or, if you also want cron jobs "load balanced", then you should find a way to synchronize/lock. (probably best in updateServerInfo or updateServers. (more details!? ..I am sure both instances will find "some object to lock on", at least the database (table, row, ..)))
As proposed by Erkan/found on internet, with "little setup" (and discarding quartz!), you can have a handy annotation for this, like:
#SchedulerLock(name = "...",
lockAtLeastForString = "...", lockAtMostForString = "...")
But I suppose, it is also possible with spring-data-jpa (only & quartz) resources, like:
Add (pessimistic) locking:
interface ApplicationServerRepository ... {
#Lock(LockModeType.PESSIMISTIC_READ)
#Query("select as from ApplicationService ...")
findAllForCron();
...
}
Catch it:
#Scheduled(cron = "0 0 * * * ?", zone = "Europe/Paris")
public void updateServers() {
try {
applicationServerRepository
.findAllForCron()
.forEach(this::updateServerInfo);
​}
catch​ (javax.persistence.PessimisticLockException plex) {
logger.info("i get some coffee");
return;
}
}

Schedule a method dinamically using cron of the annotation #Scheduled

I would Like to schedule a method using The annotation #Scheduled using cron, For example I want that the method should be executed everyday in the time specified by the client.
So I would like to get the cron value from the DB, in order to give the client the possibility of executing the method whenever he wants.
Here is my method, it sends emails automatically at 10:00 am to the given addresses, so my goal is to make the 10:00 dynamic.
Thanks for your help.
#Scheduled(cron = "0 00 10* * ?")
public void periodicNotification() {
JavaMailSenderImpl jms = (JavaMailSenderImpl) sender;
MimeMessage message = jms.createMimeMessage();
MimeMessageHelper helper;
try {
helper = new MimeMessageHelper(message, MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED, StandardCharsets.UTF_8.name());
List<EmailNotification> emailNotifs = enr.findAll();
for (EmailNotification i : emailNotifs)
{
helper.setFrom("smsender4#gmail.com");
List<String> recipients = fileRepo.findWantedEmails(i.getDaysNum());
//List<String> emails = recipientsRepository.getScheduledEmails();
String[] to = recipients.stream().toArray(String[]::new);
helper.setTo(to);
helper.setText(i.getMessage());
helper.setSubject(i.getSubject());
sender.send(message);
System.out.println("Email successfully sent to: " + Arrays.toString(to));
}
}
catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
So I'm thinking at the next solution. ( + using the answer accepted here )
Let's say you have a class that imlpements Runnable interface -> this will be your job that gets executed. Let's call it MyJob
Also assume that we have a map that hold the id of the job and it's execution reference ( you'll see in a sec what i'm talking about). Call it something like currentExecutingJobs
Assume you have an endpoint that gets the name of the job and a cron expression from the client
When that endpoints gets called:
You'll look in the map above to see if there is any entry with that job id. If it exists, you cancel the job.
After that, you'll create an instance of that job ( You can do that by using reflection and having a custom annotation on your job classes in which you can provide an id. For example #MyJob("myCustomJobId" )
And from the link provided, you'll schedule the job using
// Schedule a task with the given cron expression
ScheduledFuture myJobScheduledFutere = executor.schedule(myJob, new CronTrigger(cronExpression));
And put the result in the above map currentExecutingJobs.put("myCustomJobId", myJobScheduledFutere)
ScheduledFuture docs
In case you want to read property from database you can implement the EnvironmentPostProcessor and read the necessary values from DB and add it to Environment object, more details available at https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-spring-boot-application

initialDelay value take at runtime

I have my task to be scheduled to start after 1 min and then every 15 sec it will again run after completing my task execution. so I have my scheduler like:-
#Scheduled(initialDelay=60000, fixedDelay=15000)
public void runTask(){
// some code
}
Now I need to take initialDelay at runtime means if JVM start then I have a method "initialDelayCalculate" which calculate that, after how many hours or minute or sec my scheduler will invoke.
The time calculation method like:-
public long initialDelayCalculate(){
// time calculation
}
So it is any kind of solution to take initialDelay value from my calculation method ,like :-
#Scheduled(initialDelay={initialDelayCalculate()}, fixedDelay=15000)
public void runTask(){
// some code
}
I need a small piece of code which will solve my problem. I don't want to go for any new implementation. So please anyone can explain for any solution that how I can take value on initialDelay at runtime?
I got my solution by just calling method name as below:-
#Scheduled(initialDelayString="#{initialDelayCalculate}", fixedDelay=15000)
public void runTask(){
// some code
}
And for initialDelayCalculate method I created as bean so it will call at first when JVM up. Like:-
#Bean
public long initialDelayCalculate(){
// time calculation
}
Now it working as per my requirement. :)

What to use instead of ScheduledLockConfiguration Bean , in shedlock-spring 3.0?

I have a ScheduledLockConfiguration bean configuration.
#Bean
public ScheduledLockConfiguration taskScheduler(LockProvider lockProvider) {
return ScheduledLockConfigurationBuilder
.withLockProvider(lockProvider)
.withPoolSize(5)
.withDefaultLockAtMostFor(Duration.ofMinutes(5))
.build();
}
I just upgraded to shedlock-spring 3.0, and I don't know what to use instead of this Bean?
We can configure like below.
#Component
class TaskScheduler {
#Scheduled(cron = "0 0 10 * * ?")
#SchedulerLock(name = "TaskScheduler_scheduledTask", lockAtLeastForString = "PT5M", lockAtMostForString = "PT14M")
public void scheduledTask() {
// ...
}
}
#Scheduled will support corn format.
#SchedulerLock, the name parameter has to be unique and ClassName_methodName is typically enough to achieve that. We don't want more than one run of this method happening at the same time, and ShedLock uses the unique name to achieve that.
First, we've added lockAtLeastForString so that we can put some distance between method invocations. Using “PT5M” means that this method will hold the lock for 5 minutes, at a minimum. In other words, that means that this method can be run by ShedLock no more often than every five minutes.
Next, we added lockAtMostForString to specify how long the lock should be kept in case the executing node dies. Using “PT14M” means that it will be locked for no longer than 14 minutes.
In normal situations, ShedLock releases the lock directly after the task finishes. Now, really, we didn't have to do that because there is a default provided in #EnableSchedulerLock, but we've chosen to override that here.

spring Quartz scheduler with cron expression

I want to schedule a job class that checks if a boolean var changed to true or , which is initially not set to any value, using cron expression every night at sometime(say 1'o clock).The scheduler should quit the job if var is set to true or false, otherwise continue running the job at schedule for the max of 15 days & then set it to true automatically. I think IoC container pattern is suitable to do this. Please provide a brief picture of the whole code to implement this.
Spring has built-in scheduling capabilities. While the full implementation is in your court, here is an example of a scheduled method, in this case for 1AM every day:
private Boolean scheduleToggle = null;
#Scheduled(cron = "0 0 01 * * ?")
public void myScheduledJob() {
if(scheduleToggle != null) {
return;
} else {
// run the job
scheduleToggle = true;
return;
}
}
For a full explanation and configuration details, see: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/scheduling.html

Resources