java how to config annotation scheduler fixedDelay in properties - java

#Scheduled(cron = "0 10 0 5 * ?")
//#Scheduled(fixedDelay = 10000)
public void task() {
}
Is there a way to config :
in test env: Scheduled choose fixedDelay = 10000;
in product env: Scheduled choose cron = "0 10 0 5 * ?"
And What does this annotation grammar sugar filed=value called in java?

From spring 3.2.2 you can add this to config file and read it by Spring expression language (application.properties or application.yml)
application.yml
scheduler:
fixedDelay: 1000
In java class
#Scheduled(fixedDelayString = "${scheduler.fixedDelay}")
public void task() {
}
Note : Before 3.2.2 it will accept only long value but from 3.2.2 it will accept string also

Related

Spring Scheduling - Cron expression for every month end at 11PM?

I would like to run cron expression at 11:10 pm of very month ending. I am trying to write by following link A Guide To Cron Expressions but I am unable to write. Sample code is below is this will work fine.
#Scheduled(cron = "0 10 23 L * ? *")
public void scheduleTaskWithCronExpression() {
System.out.println("Cron Task");
}
Try with this:
#Scheduled(cron = "0 10 23 L * ?")
For generate or check corn expression use this
You can also try with time zone
#Scheduled(cron = "0 10 23 L * ?", zone = "CET")
public void scheduleTaskWithCronExpression() {
System.out.println("Cron Task");
}

Add scripts dynamically as jobs using property/xml file in Quartz

Scenario : I want to create a scheduler application which should run shell scripts as per the defined schedule. To keep it simple, I want the user to add script name and execution timings in some external file (properties/xml) which will be used by my application. For now, I am planning to run this application as a background process on Linux server. In future may be we'll make it as a web-app.
What I've tried till now:
I came across xmlschedulingdataprocessorplugin for this purpose but it requires user to write jobs as Java code and then add it in XML file.
I found some examples for scheduling which presently isn't working.
Please suggest some helpful quartz API which can help me in fulfilling this purpose.
UPDATE:
public class CronTriggerExample {
public static void main(String[] args) throws Exception {
String[] a = {"script1.sh:0/10 * * * * ?", "script2.sh:0/35 * * * * ?"};
for (String config : a) {
String[] attr = config.split(":");
System.out.println("Iterating for : "+attr[0]);
JobKey jobKey = new JobKey(attr[0], attr[0]);
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity(attr[0], attr[0])
.withSchedule(CronScheduleBuilder.cronSchedule(attr[1]))
.build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.getContext().put("val", config);
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity(jobKey).build();
scheduler.start();
scheduler.scheduleJob(job, trigger);
System.out.println("=======================");
}
}
}
My HelloJob class:
public class HelloJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
String objectFromContext = null;
Date date = new Date();
try {
SchedulerContext schedulerContext = context.getScheduler().getContext();
objectFromContext = (String) schedulerContext.get("val");
} catch (SchedulerException ex) {
ex.printStackTrace();
}
System.out.println("Triggered "+objectFromContext+" at: "+date);
}
}
OUTPUT:
Iterating for : script1.sh
log4j:WARN No appenders could be found for logger (org.quartz.impl.StdSchedulerFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
=======================
Iterating for : script2.sh
=======================
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:21:50 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:00 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:00 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:10 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:20 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:30 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:35 IST 2016
Triggered script2.sh:0/35 * * * * ? at: Mon Apr 18 12:22:40 IST 2016
What am I missing? I tried to create new Job for each iteration and assign script names as JobExecutionContext
The below tutorial help you to schedule shell script.
http://www.mkyong.com/java/how-to-run-a-task-periodically-in-java/
By using
Runtime.getRuntime().exec("sh shellscript.sh");
You can run shell script.
I would take the following approach :
You create a class JobShellRunner which will implement Job interface from quartz :
public class JobShellRunner implements Job {
#Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
// here you take need information about the shell script you need to run, from the context and run the shell script
}
}
read properties files (i suppose here it will be available information about which shell script to run and it's schedule information). For each information needed you will create it's context and it's trigger:
JobKey jobKey = new JobKey("jobShellRunner", "group1");
// put in the job key need information about shell script (path, etc)
JobDetail jobA = JobBuilder.newJob(JobShellRunner.class)
.withIdentity(jobKey).build();
Then the trigger (note that on the cron expression you should complete with the one that you read from properties file):
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("dummyTriggerName1", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
.build();
Then schedule the job
scheduler.scheduleJob(jobA, trigger);
you can do something like as following way,
First of need to go likewise,
create your java application which has one scheduled-job which will read at
some time interval one propery/xml file which will provide an information
for which shell_file needs to execute and at what time.
While your program's scheduled-job read that property/xml file and getting
information as following,
2.1. Shell-Script-File-Name
2.2. Timing at what time that script needs to be execute.
This information which is read by above(step-2), with help of it, this job
will create newer independent-job which is fully responsible for execute
shell script at particular time.(that time will be your job-time which is
read from your propery/xml file). also take care of it to it should be one time only(as per your requirement).
this above step repeatedly does untill whole information read by this job and every time will generate one newer job.
in case after some time user edit/updated/added new line into property/xml file this java program's scheduled job will read only
that newer changes and accordingly does as like above explained.
you can see below image for better understanding purpose,
For scheduling purpose you can set-up spring-quartz API for schedule job.
here, I am going to give you little bit pseudo code,
public class JobA implements Job {
#Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
// continues read property/xml file untill while file not read
// based upon above read info. generate new job(one time only) at runtime which has capability to execute shell script
// shell script can be execute by java program by this ,
// Runtime.getRuntime().exec("sh /full-path/shell_script_name.sh");
}
}
............
public class CronTriggerExample {
public static void main( String[] args ) throws Exception
{
JobKey jobKeyA = new JobKey("jobA", "group1");
JobDetail jobA = JobBuilder.newJob(JobA.class)
.withIdentity(jobKeyA).build();
Trigger trigger1 = TriggerBuilder
.newTrigger()
.withIdentity("dummyTriggerName1", "group1")
.withSchedule(
CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) // you can set here your comfortable job time...
.build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(jobA, trigger1);
}
}
So, this is an idea what I believe and represent over here, which is top-most suitable as per your requirement.

Grails groovy too many hibernate connections

I am struggling with manual the transaction management. Background: I need to run quarz crons which run batch processes. It is recommended for batch processing to manually decide when to flush to the db to not slow down the application to much.
I have a pooled hibernate connection as the following
dataSource {
pooled = true
driverClassName = "com.mysql.jdbc.Driver"
dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"
properties {
maxActive = 50
maxIdle = 25
minIdle = 1
initialSize = 1
minEvictableIdleTimeMillis = 60000
timeBetweenEvictionRunsMillis = 60000
numTestsPerEvictionRun = 3
maxWait = 10000
testOnBorrow = true
testWhileIdle = true
testOnReturn = false
validationQuery = "SELECT 1"
validationQueryTimeout = 3
validationInterval = 15000
jmxEnabled = true
maxAge = 10 * 60000
// http://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html#JDBC_interceptors
jdbcInterceptors = "ConnectionState;StatementCache(max=200)"
}
}
hibernate {
cache.use_second_level_cache = false
cache.use_query_cache = false
cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory'
show_sql = false
logSql = false
}
the cron job calls a service in the service i run do the following:
for(int g=0; g<checkResults.size() ;g++) {
def tmpSearchTerm = SearchTerm.findById((int)results[g+i][0])
tmpSearchTerm.count=((String)checkResults[g]).toInteger()
batch.add(tmpSearchTerm)
}
//increase counter
i+=requestSizeTMP
if (i%(requestSize*4)==0 || i+1==results.size()){
println "PREPARATION TO WRITE:" + i
SearchTerm.withSession{
def tx = session.beginTransaction()
for (SearchTerm s: batch) {
s.save()
}
batch.clear()
tx.commit()
println ">>>>>>>>>>>>>>>>>>>>>writing: ${i}<<<<<<<<<<<<<<<<<<<<<<"
}
session.flush()
session.clear()
}
}
So I am adding things to a batch until I have enough (4x the request size or the last item) and then I am trying to write it to the db.
Everything works fine.. but somehow the code seems to open hibernate transactions and does not close them. I don't really understand why but I am getting a hard error and tomcat crashes with too many connections. I have 2 Problems with that, which i do not understand:
1) If the dataSource is pooled and the maxActive is 50 how can i get a too many connection errors if the limit of tomcat is 500.
2) How do I explicitly terminate the transaction so that i do not have so many open connections?
You can use withTransaction because it will manage transaction.
For example
Account.withTransaction { status ->
def source = Account.get(params.from)
def dest = Account.get(params.to)
int amount = params.amount.toInteger()
if (source.active) {
source.balance -= amount
if (dest.active) {
dest.amount += amount
}
else {
status.setRollbackOnly()
}
}
}
You can look about withTransaction in http://grails.org/doc/latest/ref/Domain%20Classes/withTransaction.html
You can see the difference between withSession and withTransaction in https://stackoverflow.com/a/19692615/1610918
------UPDATE-----------
But I would prefer you to use service and it can be called from job.

quartz.properties cant access mysql : Could not load driverClass com.mysql.jdbc.Driver

i am struggling to resolve this matter, i have try to run a small test to connect with my mysql and it work.but when i am trying to work with quartz.properties it cannot access mysql.
i am sure my jdbc mysql driver is fine. as other than using quartz.properties, i can access my mysql database.
i need help. i have work on this for days now.
here is the part i suspect have problem
#The details of the datasource specified previously
org.quartz.dataSource.myDS.driver =com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL =jdbc:mysql://10.1.1.111:3306/somedatabase
org.quartz.dataSource.myDS.user =username
org.quartz.dataSource.myDS.password =somepassword
org.quartz.dataSource.myDS.maxConnections = 20
error output:
207 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'MyScheduler' initialized from default file in current working dir: 'quartz.properties'
208 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.2.1
267 [main] DEBUG com.mchange.v2.resourcepool.BasicResourcePool - incremented pending_acquires: 1
267 [main] DEBUG com.mchange.v2.resourcepool.BasicResourcePool - incremented pending_acquires: 2
268 [main] DEBUG com.mchange.v2.resourcepool.BasicResourcePool - incremented pending_acquires: 3
268 [main] DEBUG com.mchange.v2.resourcepool.BasicResourcePool - com.mchange.v2.resourcepool.BasicResourcePool#42af94c4 config: [start -> 3; min -> 1; max -> 20; inc -> 3; num_acq_attempts -> 30; acq_attempt_delay -> 1000; check_idle_resources_delay -> 0; mox_resource_age -> 0; max_idle_time -> 0; excess_max_idle_time -> 0; destroy_unreturned_resc_time -> 0; expiration_enforcement_delay -> 0; break_on_acquisition_failure -> false; debug_store_checkout_exceptions -> false]
269 [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2] WARN com.mchange.v2.c3p0.DriverManagerDataSource - Could not load driverClass com.mysql.jdbc.Driver
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:190)
Here is my quartz code
public class QuartzDaily {
static Logger log = Logger.getLogger("QuartzDaily");
public static void main(String[] args) throws ParseException, SchedulerException, IOException, NoSuchAlgorithmException
{
//lines of codes to configure log
DateFormat format3 = new SimpleDateFormat( "MM_dd_yyyy_HH_mm" );
Date dateToday = new Date();
String strToday= format3.format(dateToday);
BasicConfigurator.configure();
PatternLayout pattern = new PatternLayout("%r [%t] %-5p %c %x - %m%n");
FileAppender fileappender = new FileAppender(pattern,"log\\QuartzScheduler_"+strToday+".txt");
log.addAppender(fileappender);
log.info("QuartzReport; main(): [** Starting scheduler services **]");
//run quartz job
quartzWeekly();
}
public static void quartzWeekly() throws SchedulerException{
//some quartz job code
}
public static class TestJob implements Job {
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("hello world");
}
}
}
Below is the full code, below code is not mine, it was taken from random tutorial site.
#Skip Update Check
#Quartz contains an "update check" feature that connects to a server to
#check if there is a new version of Quartz available
org.quartz.scheduler.skipUpdateCheck: true
org.quartz.scheduler.instanceName =MyScheduler
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 4
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.threadPool.threadPriority = 5
#specify the jobstore used
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties = false
#specify the TerracottaJobStore
#org.quartz.jobStore.class = org.terracotta.quartz.TerracottaJobStore
#org.quartz.jobStore.tcConfigUrl = localhost:9510
#The datasource for the jobstore that is to be used
org.quartz.jobStore.dataSource = myDS
#quartz table prefixes in the database
org.quartz.jobStore.tablePrefix = qrtz_
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.isClustered = false
#The details of the datasource specified previously
org.quartz.dataSource.myDS.driver =com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL =jdbc:mysql://10.1.1.11:3306/somedatabase
org.quartz.dataSource.myDS.user =username
org.quartz.dataSource.myDS.password =somepassword
org.quartz.dataSource.myDS.maxConnections = 20
#Clustering
#clustering currently only works with the JDBC-Jobstore (JobStoreTX
#or JobStoreCMT). Features include load-balancing and job fail-over
#(if the JobDetail's "request recovery" flag is set to true). It is important to note that
# When using clustering on separate machines, make sure that their clocks are synchronized
#using some form of time-sync service (clocks must be within a second of each other).
#See http://www.boulder.nist.gov/timefreq/service/its.htm.
# Never fire-up a non-clustered instance against the same set of tables that any
#other instance is running against.
# Each instance in the cluster should use the same copy of the quartz.properties file.
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
#Each server must have the same copy of the configuration file.
#auto-generate instance ids.
org.quartz.scheduler.instanceId = AUTO
#Note :
#If a job throws an exception, Quartz will typically immediately
#re-execute it (and it will likely throw the same exception again).
#It's better if the job catches all exception it may encounter, handle them,
#and reschedule itself, or other jobs. to work around the issue.
I had the exact same issue and I fixed it by adding mysql connector jar in WEB-INF/lib. Please make sure that the WEB-INF is marked as a source folder in build path.

Quartz scheduleJob Exceptions

Ok, so here I've got a Quartz(version 2.2.1) job that should instantiate two other jobs, create and add two triggers for each job, and add both jobs to the scheduler, deleting them after a set interval that's passed in through the JobDataMap.
When this job is run by the scheduler, it throws the following exception:
org.quartz.JobPersistenceException: The job (DEFAULT.countdown15, countdownGroup) referenced by the trigger does not exist.
The exception is thrown at line 71:
sched.scheduleJob(countdown15Trigger2);
I couldn't figure out why the job doesn't exist at that point, since it should have been created by the earlier newJob call and added to the scheduler by line 70:
sched.scheduleJob(countdown15, countdown15Trigger1);
So, I temporarily commented out that line and attempted to run the program again, whereupon I got this exception at line 72:
line 72:
sched.scheduleJob(countdown60, countdown60Trigger1);
exception:
org.quartz.SchedulerException: Trigger does not reference given job!
Ok, so now I've got two scheduleJob calls throwing two different exceptions, even though as far as I can tell I'm following the correct syntax. But the first scheduleJob call must be working correctly, because the exceptions are occurring later in the code, so for now I'll comment out all the other scheduleJob calls and see what happens.
And then I get this error at line 70, the first and now only scheduleJob call:
org.quartz.ObjectAlreadyExistsException: Unable to store Job : 'countdownGroup.countdown15', because one already exists with this identification.
I don't really know where to go from here, so here's the complete code for the top level job. Any ideas?
public class ShowClockJob implements Job {
public ShowClockJob() {}
#Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
JobDataMap dm = context.getJobDetail().getJobDataMap();
int min = dm.getInt("min"); //show's runtime in minutes
int ms = min * 60000; //convert the runtime in minutes to millisec
Scheduler sched = context.getScheduler();
JobDetail countdown15 = newJob(CountdownJob15.class)
.withIdentity(jobKey("countdown15", "countdownGroup"))
.build();
JobDetail countdown60 = newJob(CountdownJob60.class)
.withIdentity("countdown60", "countdownGroup")
.build();
Trigger countdown15Trigger1 = newTrigger()
.withIdentity("countdown15Trigger1", "countdownGroup")
.withSchedule(cronSchedule("45 5 * * * ?")
.withMisfireHandlingInstructionDoNothing())
.forJob(jobKey("countdown15", "countdownGroup"))
.build();
Trigger countdown15Trigger2 = newTrigger()
.withIdentity("countdown15Trigger2", "countdownGroup")
.withSchedule(cronSchedule("55 19,32,46 * * * ?")
.withMisfireHandlingInstructionDoNothing())
.forJob(jobKey("countdown15, countdownGroup"))
.build();
Trigger countdown60Trigger1 = newTrigger()
.withIdentity("countdown60Trigger1", "countdownGroup")
.withSchedule(cronSchedule("0 17,29,44 * * * ?")
.withMisfireHandlingInstructionDoNothing())
.forJob(jobKey("countdown60, countdownGroup"))
.build();
Trigger countdown60Trigger2 = newTrigger()
.withIdentity("countdown60Trigger2", "countdownGroup")
.withSchedule(cronSchedule("50 57 * * * ?")
.withMisfireHandlingInstructionDoNothing())
.forJob("countdown60, countdownGroup")
.build();
try {
sched.scheduleJob(countdown15, countdown15Trigger1);
sched.scheduleJob(countdown15Trigger2);
sched.scheduleJob(countdown60, countdown60Trigger1);
sched.scheduleJob(countdown60Trigger2);
Thread.sleep(ms); //sleep for the length of the showtime,
//...then shut down the countdown jobs
sched.deleteJob(jobKey("countdown15","countdownGroup"));
sched.deleteJob(jobKey("countdown60","countdownGroup"));
} catch (SchedulerException | InterruptedException ex) {
Logger.getLogger(ShowClockJob.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Turns out it was a simple syntax error. In all but the first trigger creation blocks, at the forJob method, I left out the middle two parenthesis that seperated the jobKey and jobGroup into two strings.
So this:
forJob("countdown60, countdownGroup");
Should have been this:
forJob("countdown60", "countdownGroup");

Categories

Resources