spring Quartz scheduler with cron expression - spring

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

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

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.

springs scheduing jobs for a given

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.

Quartz Integration with Spring

I have a web application and I am trying to start Quartz scheduler programmatically in spring. I have a service class where I create an instance of SchedulerFactory and then get a scheduler.
The code is as follows.
#Service("auctionWinnerService")
public class NormalAuctionWinnerServiceImpl implements AuctionWinnerService {
public static final String NORMAL_AUCTION = "NORMAL AUCTION";
public static int NORMAL_AUCTION_COUNTER = 0;
private SchedulerFactory schedulerFactory;
private Scheduler scheduler;
public void declareWinner(int auctionId, Map<String, Object> parameterMap) {
System.out.println("INSIDE declareWinner of NormalAuctionWinner");
schedulerFactory = new StdSchedulerFactory();
try {
scheduler = schedulerFactory.getScheduler();
System.out.println("GOT SCHEDULER : "+scheduler);
} catch (SchedulerException e1) {
e1.printStackTrace();
}
JobDetail jd = new JobDetail();
jd.setName(NORMAL_AUCTION+" JOB "+NORMAL_AUCTION_COUNTER);
jd.setJobClass(NormalAuctionWinnerJob.class);
/** CREATE CRON TRIGGER INSTANCE **/
CronTrigger t = new CronTrigger();
t.setName(NORMAL_AUCTION + ++NORMAL_AUCTION_COUNTER);
t.setGroup("Normal Auction");
Date d = new Date();
Date d1 = new Date();
d1.setMinutes(d.getMinutes()+5);
t.setStartTime(d);
t.setEndTime(d1);
try {
t.setCronExpression("10 * * * * ? *");
scheduler.scheduleJob(jd, t);
} catch (SchedulerException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}
The schedulerFactory and scheduler are instantiated but my jobs do not run.
Could someone point out what am I missing here?
Also I need only one instance of Factory and one scheduler instance. I tried making the static but it didn't work. Any pointers in this direction will be helpful.
Thanks
Unless you have a specific requirement on Quartz's proprietary functionality, I recommend getting rid of it and using Spring's internal scheduling capability. As of Spring 3, this includes support for cron-type expressions, very similar to Quartz's cron trigger.
As well as bringing simplicity to your application and its config, it's inherently more reliable than Quartz, and provides an easier API for programmatic usage, via the TaskScheduler interface.
First of all, how well do you know Quartz or cron trigger expressions? I may be mistaken, but 10 * * * * ? * will make the trigger fire every 10th second of every minute, but I've never seen such expression, it may not fire at all.
Are you trying to create a trigger to fire every 10 seconds? In this case, use a simple trigger like this:
new SimpleTrigger((NORMAL_AUCTION + ++NORMAL_AUCTION_COUNTER),
"Normal Auction",
d,
d1,
SimpleTrigger.REPEAT_INDEFINITELY,
10000L);
Edit:
Ok, so if that's you requirement, you need a trigger that fill fire just once, at the end time of the auction. For that, use a SimpleTrigger like this:
new SimpleTrigger((NORMAL_AUCTION + ++NORMAL_AUCTION_COUNTER),
"Normal Auction",
d1,
null,
0,
0L);
The start date in this case does not matter, as long as you set it to fire on the appropriate time (the end time) and just once.
And as an additional note, do not calculate dates like that. I suggest you to try Joda Time library. Really simple and well known replacement for the clumsy standard Date/Calendar API.
You have forgotten to start the scheduler! scheduler.start();
...
try {
t.setCronExpression("10 * * * * ? *");
scheduler.scheduleJob(jd, t);
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
I have proved this, after adding the missing statement, (and replacing the job with an dummy) it worked for me/

Resources