I'm using Spring 3.0.2 version to run my Java/Flex application.
The task is that "Every new year at 12.00 A.M I need to reset a column value to zero on database". But the scheduler is not executing the configured method.
But if I change the corn expression to other form, for eg: run every the scheduler for every 50 secs it works perfectly.
Below is the cron expression which has been configured on properties file.
cron1.expression = 0 0 0 1 1 ?
Configuration in Application context.
<task:annotation driven/>
<util:properties id="javaScheduler" location="WEB-INF/javaScheduler.properties"/>
<context:property-placeholder properties-ref="javaScheduler"/>
<task:scheduled-tasks>
<task:scheduled ref="schedulerDAO" method="updateSampleRegistrationSeqno"
cron="#{javaScheduler['cron1.expression']}"/>
</task:scheduled-tasks>
Configured Method:
public void updateSampleRegistrationSeqno() throws Exception
{
try
{
logging.info("<<<<<<<<<<<<<<<<<<<----Updating sample registration series code in Seqnotransgenerator of table name All ---->>>>>>>>>>>>>>>>>>");
//String sp = "exec dbo.sp_SequenceUpdateNewYear";
getJdbcTemplate().execute("update SequencenoTransGenerator set nsequenceno = 0 where stablename = 'All'");
}
catch(Exception e)
{
logging.info("Exception occured at updateSampleRegistrationSeqno :------->"+e.getLocalizedMessage());
}
}
Add these two lines in your application context:
<context:property-placeholder location="classpath:/properties/app.properties"/>
or
<context:property-placeholder location="file:/properties/app.properties"/>
<task:annotation-driven></task:annotation-driven>
Schedule task:
#Scheduled(cron = "${cronexp}")
public void executeTask() {
//execute sql script
}
Add this cron expression in your properties file:
cronexp=0 0 0 1 1 ?
It worked for me.
Note: at location you should provide you properties path
Related
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;
}
}
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
I have implemented a scheduler with shedlock in my current spring project as follows:
#Scheduled(cron = "0 0/1 * * * *")
#SchedulerLock(name = "syncData",
lockAtMostFor = "${shedlock.myScheduler.lockAtMostFor}",
lockAtLeastFor = "${shedlock.myScheduler.lockAtLeastFor}")
public void syncSAData() {
//To assert that the lock is held
LockAssert.assertLocked();
...
}
Now I would like to write unit test for this function. Here the problem I am facing is: I am unable to mock first statement: LockAssert.assertLocked().
This should do the trick LockAssert.TestHelper.makeAllAssertsPass(true);
Just add it at the beginning of the test method.
Docs: https://github.com/lukas-krecan/ShedLock#lock-assert
in our system we use a settings class to point to the properties file, depends on which eve it loads different property file. To access specific property, we call 'Settings.getString('property_name_here')'.
In my code, i loaded the #scheduled cron expression to a variable and try to passed to the #scheduled annotation, but it won't work,
here is my code:
in properties file:
cron.second=0
cron.min=1
cron.hour=14
in constructor i have:
this.cronExpression = new StringBuilder()
.append(settings.getString("cron.second"))
.append(" ")
.append(settings.getString("cron.min"))
.append(" ")
.append(settings.getString("cron.hour"))
.append(" ")
.append("*").append(" ").append("*").append(" ").append("*")
.toString();
which create a String of "0 1 14 * * *", it's a valid con expression
in the scheduled task i have:
#Scheduled(cron = "${this.cronExpression}")
public void scheduleTask() throws Exception {
....
}
when I ran the code it complaint:
Caused by: java.lang.IllegalStateException: Encountered invalid #Scheduled method 'scheduleTask': Cron expression must consist of 6 fields (found 1 in "${this.cronExpression}")
then I changed this.cronExpression to a list of String:
this.cronExpression = Lists.newArrayList();
this.cronExpression.add(settings.getString("cron.second"));
this.cronExpression.add(settings.getString("cron.min"));
this.cronExpression.add(settings.getString("cron.hour"));
this.cronExpression.add("*");
this.cronExpression.add("*");
this.cronExpression.add("*");
but still got the same error, so what exactly is the cron expression supposed to be?
What I did and it worked for me:
In properties file:
my.cron.expression=0 3 * * * ?
In code:
#Scheduled(cron = "${my.cron.expression}")
public void scheduleTask(){
...
}
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