I am struggling this for a week.
using Jboss5.1.x, EJB3.0, quartz1.8
people refer me to to documents, but it seems like no1 has really clue or doesn't understand me.
Is there a way of starting the java code in EJB bean to schedule quartz?
I already understood how to init and loop up the quartz scheduler.. but how do you actually call the method which INIT the scheduler on application deployment?
if you need the JBOSS scheduler to first call the init method which schedule Quartz, then Quartz is useless for me! i would just continue with Jboss scheduler.
anyone has any solution for that?
thanks,
ray.
I'm not sure I understand your question but can't you store the Quartz scheduler factory in a static variable and initialize it in a static initializer or a static method? Something like:
public static Scheduler sched;
public static void init(ServletContext servletContext) throws SchedulerException {
if (sched == null || !sched.isStarted()) {
String quartzPropertiesLocation = UtilityClass.getYourQuartzConfig();
try {
log.info(new File(quartzPropertiesLocation).getCanonicalPath());
} catch (IOException e) {
e.printStackTrace();
}
SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory(quartzPropertiesLocation);
sched = schedFact.getScheduler();
sched.getContext().put(ServletContext.class.getName(), servletContext);
sched.start();
}
}
Yes, but What I wanted to achive is to have my quartz start on deploy. but I found solution for this I am using
#Service(objectName = "..")
#Management(...)
and that class will be triggerd as soon as my project will deploy.
Related
I have a process which is an infinite loop:
public class MyProcess {
public void start() {
while (true) {
//process
}
}
}
When I started using Spring Boot, my first approach was to get the bean from the context after the application had started and manually start the process:
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(MyApplication.class, args);
MyProcess myProcess = applicationContext.getBean(MyProcess.class);
myProcess.start();
}
}
This worked but did not seem like the right way of doing it, so I implemented a CommandLineRunner:
#Component
public class MyRunner implements CommandLineRunner {
#Autowired
private MyProcess myProcess;
#Override
public void run(String... args) {
this.myProcess.start();
}
}
This is almost the same as before, but here the SpringApplication#run call never actually finishes, which seems also wrong. Am I correct to think that?
I then tried to manage this on my own with an Executor, but in order to catch any Exception I had to call Future#get which resulted in the same blocking state.
Instead of this, I am now using an #Async annotation on the CommandLineRunner#run method.
This seems to be the best solution as the application finishes starting after the task has also been started. Any Exception will be picked up and logged, but the backing Executor created by Sprint prevents the application from shutting down.
I assume there is a way of asking Spring to terminate the Executor so that the entire application can exit since I am managing it externally with Supervisor.
Is this the correct approach or am I missing a step? Should the application be independent and restart the process after a failure?
Do some work in the main thread. What is wrong with calling myProcess.start() from main() without #Async? When you finish your job just leave loop in MyProcess#start
Hi i am creating an application that executes the method of a class based on a cron expression. For that i am using spring quartz in which i have to configure all these stuffs in my spring-file it works fine and jobs are executing based on the cron expression, But now i want to suspend the next execution of particular job in java class based on the choice of a user from UI. Then is there any way to do this ??
can i get the details of all running job it the context ? if so then i can filter the jobs and try to suspend that job for next execution.
Inject your SchedulerFactoryBean. Use it's getScheduler method to obtain a quartz Scheduler and use rescheduleJob or other methods from quartz API to perform your task.
I got it work by use of following code
stdScheduler is a scheduleFactoryBean
String groupnames[] = stdScheduler.getJobGroupNames();
for (String groupName : groupnames) {
String[] jobNames = stdScheduler.getJobNames(groupName);
for (String jobName : jobNames) {
if (jobName.equals("jobName")) {
stdScheduler.pauseJob(jobName, groupName);
}
}
}
We can use the stdScheduler.pauseJob(JobKey jobKey) method to reduce the number of loops mentioned in the code above
If you got hold of the SchedulerFactoryBean by injection or somehow else there are the convenience methods:
schedulerFactoryBean.getScheduler().standby();
schedulerFactoryBean.getScheduler().start();
When using Quartz directly also this works:
#Autowired
private Scheduler scheduler;
...
scheduler.standby();
...
scheduler.start();
I've a web application which uses framework like Struts and Hibernate. Currently I'm developing a scheduler for this application using Quartz. While coding I realized that the use of Hibernate session is not possible with the threads of Quartz.
Anybody have a solution for using hibernate sessions from quartz job class?
One approach is to use a HibernateUtil class which builds the SessionFactory in a static initializer and makes it available via a public static getter. Your Quartz job can create a Session as HibernateUtil.getSessionFactory().getCurrentSession() and use it.
I know this is an old question, but I did a quick Google search, and this was the first hit.
In the quartz job, add this line at the start of the method:
public void execute(JobExecutionContext context) throws JobExecutionException
{
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); //<-- this line
//...your code here...
}
I apologize if this doesn't fix your specific issue, but I suspect it will catch someone in the future.
Searching for "Quartz Hibernate" returned this. Coming to a different solution (and using Tapestry), I thought I'd share it.
when scheduling the Job:
…
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
JobDataMap myJobDataMap = new JobDataMap();
myJobDataMap.put("HibernateSessionManager", hibernateSessionManager);
myJobDataMap.put("PerthreadManager", perThreadManager);
JobDetail job = JobBuilder.newJob(SomeJob.class).withIdentity(
"SomeJob", "someGroup").setJobData(
myJobDataMap).build();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(
"Some Trigger", "someGroup").startNow().withSchedule(
SimpleScheduleBuilder.repeatSecondlyForever(30)).build();
scheduler.scheduleJob(job, trigger);
scheduler.start();
…
and in the Job
public void execute(JobExecutionContext context)
throws JobExecutionException
{
JobDataMap jdm = context.getMergedJobDataMap();
HibernateSessionManager hibernateSessionManager = (HibernateSessionManager) jdm.get("HibernateSessionManager");
PerthreadManager perThreadManager = (PerthreadManager) jdm.get("PerthreadManager");
Session session = hibernateSessionManager.getSession();
//do stuff with session …
//now clean up, otherwise I ended up with <IDLE> in transactions
perThreadManager.cleanUp();
}
Hope somebody can use this.
You can look at the below link to see if it gives you a direction to follow. Since you are not using Spring, it might be hard to apply this directly
http://forum.springsource.org/showthread.php?t=12117
Is there a way I could run a job only once using Quartz in Java? I understand it does not make sense to use Quartz in this case. But, the thing is, I have multiple jobs and they are run multiple times. So, I am using Quartz.
Is this even possible?
You should use SimpleTrigger that fires at specific time and without repeating. TriggerUtils has many handy methods for creating these kind of things.
Yes, it's possible!
JobKey jobKey = new JobKey("testJob");
JobDetail job = newJob(TestJob.class)
.withIdentity(jobKey)
.storeDurably()
.build();
scheduler.addJob(job, true);
scheduler.triggerJob(jobKey); //trigger a job inmediately
In quartz > 2.0, you can get the scheduler to unschedule any job after work is done:
#Override
protected void execute(JobExecutionContext context)
throws JobExecutionException {
...
// process execution
...
context.getScheduler().unscheduleJob(triggerKey);
...
}
where triggerKey is the ID of the job to run only once. After this, the job wouldn't be called anymore.
Here is an example of how to run a TestJob class immediately with Quartz 2.x:
public JobKey runJob(String jobName)
{
// if you don't call startAt() then the current time (immediately) is assumed.
Trigger runOnceTrigger = TriggerBuilder.newTrigger().build();
JobKey jobKey = new JobKey(jobName);
JobDetail job = JobBuilder.newJob(TestJob.class).withIdentity(jobKey).build();
scheduler.scheduleJob(job, runOnceTrigger);
return jobKey;
}
see also Quartz Enterprise Job Scheduler Tutorials → SimpleTriggers
I'm not sure how much similar is Quartz in Mono and Java but this seems working in .Net
TriggerBuilder.Create ()
.StartNow ()
.Build ();
I had to ask myself if it made sense to try to configure a job and add checks if it had been run already as suggested in Marko Lahma's answer (since scheduling a job to run once results in it being run once, every time we start the app). I found examples of CommandLineRunner apps which didn't quite work for me, mostly because we already had an ApplicationRunner which was used for other jobs which use Quartz scheduling / cron. I wasn't happy with having Quartz initialize this job using a SimpleTrigger, so I had to find something else.
Using some ideas from the following articles:
Multiple Spring boot CommandLineRunner based on command line argument
Run Spring Batch Job programmatically?
Firing Quartz jobs manually
Is there any way to get job keys in Quartz by job name
How to list all Jobs in the Quartz Scheduler
Spring Boot CommandLineRunner and ApplicationRunner
I was able to piece together a working implementation which allows me to do the following:
run existing jobs via Quartz, on a timer
run new job, one time programmatically (single use Quartz job using the SimpleTrigger didn't satisfy my requirements, since it would be run once on every application load)
I came up with the following CommandLineRunner class:
public class BatchCommandLineRunner implements CommandLineRunner {
#Autowired
private Scheduler scheduler;
private static final Logger LOGGER = LoggerFactory.getLogger(BatchCommandLineRunner.class);
public void run(final String... args) throws SchedulerException {
LOGGER.info("BatchCommandLineRunner: running with args -> " + Arrays.toString(args));
for (final String jobName : args) {
final JobKey jobKey = findJobKey(jobName);
if (jobKey != null) {
LOGGER.info("Triggering job for: " + jobName);
scheduler.triggerJob(jobKey);
} else {
LOGGER.info("No job found for jobName: " + jobName);
}
}
}
private JobKey findJobKey(final String jobNameToFind) throws SchedulerException {
for (final JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals("DEFAULT"))) {
final String jobName = jobKey.getName();
if (jobName.equals(jobNameToFind)) {
return jobKey;
}
}
return null;
}
}
In one of my configuration classes I added a CommandLineRunner bean which calls the custom CommandLineRunner I created:
#Configuration
public class BatchConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(BatchConfiguration.class);
#Bean
public BatchCommandLineRunner batchCommandLineRunner() {
return new BatchCommandLineRunner();
}
#Bean
public CommandLineRunner runCommandLineArgs(final ApplicationArguments applicationArguments) throws Exception {
final List<String> jobNames = applicationArguments.getOptionValues("jobName");
LOGGER.info("runCommandLineArgs: running the following jobs -> " + ArrayUtils.toString(jobNames));
batchCommandLineRunner().run(jobNames.toArray(ArrayUtils.EMPTY_STRING_ARRAY));
return null;
}
}
Later, I am able to initiate these jobs via the CLI without affecting my current Quartz scheduled jobs, and as long as no one runs the command via CLI multiple times, it will never be run again. I have to do some juggling of types since I accept ApplicationArguments, and then convert them into String[].
Finally, I am able to call it like this:
java -jar <your_application>.jar --jobName=<QuartzRegisteredJobDetailFactoryBean>
The result is that the job is initialized only when I call it, and it is excluded from my CronTriggerFactoryBean triggers which I used for my other jobs.
There are several assumptions being made here, so I'll try to summarize:
the job must be registered as a JobDetailFactoryBean (e.g.: scheduler.setJobDetails(...))
everything is essentially the same as a job with CronTriggerFactoryBean, excepting the lacking scheduler.setTriggers(...) call
Spring knows to execute the CommandLineRunner classes after the application has booted
I hardcoded the parameter being passed into the application to "jobName"
I assumed a group name of "DEFAULT" for all jobs; if you want to use differing groups this would need to be adjusted when fetching JobKey, which is used to actually run the job
there is nothing which prevents this job from being run multiple times via CLI, but it was triggered on every application load using SimpleTrigger approach, so this is better for me; if this is not acceptable, perhaps using StepListener and ExitStatus, etc. can prevent it from being executed twice
Another solution: There is a method .withRepeatCount(0) in SimpleSchedulerBuilder:
public final int TEN_SECONDS = 10;
Trigger trigger = newTrigger()
.withIdentity("myJob", "myJobGroup")
.startAt(new Date(System.currentMillis()+TEN_SECONDS*1000)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withRepeatCount(0)
.withIntervalInMinutes(1))
.build();
I'm trying to wire together Guice (Java), Quartz scheduler and iBatis (iBaGuice) to do the following:
Start command line utility-scanner using main()
Periodically scan directory (provided as argument) for files containing formatted output (XML or YAML)
When file is detected, parse and output result to the database
The problems:
I used this example to wire Guice and Quartz. However I'm missing some important details which I'm asking in the comments but the post is somewhat dated so I'm quoting it here also:
It's not obvious how to set-up the scheduler. Where and how would I wire the Trigger (I can use Trigger#makeMinutelyTrigger)?
I really have just one type of job I will be executing, I understand that details in the JobFactory#newJob are coming from the TriggerFiredBundle parameter but where/how do I wire that? And where/how do I create or wire concrete Job?
P.S. I got a little bit further by creating and wiring ScheduleProvider. Now I'm stuck with how to actually schedule the Job in this following snippet. It seams that my JobFactory#newJob method is never called
public class CollectorServiceImpl implements CollectorService {
Scheduler scheduler;
/**
* #throws SchedulerException
*/
#Inject
public CollectorServiceImpl(final SchedulerFactory factory, final GuiceJobFactory jobFactory)
throws SchedulerException {
scheduler = factory.getScheduler();
scheduler.setJobFactory(jobFactory);
}
/**
* #throws SchedulerException
* #see teradata.quantum.reporting.collector.service.CollectorService#start()
*/
#Override
public void start() throws SchedulerException {
Trigger trigger = TriggerUtils.makeMinutelyTrigger("MIN_TRIGGER");
scheduler.scheduleJob(trigger); // this fails trigger validation since no job name is provided
scheduler.start();
}
}
core to your problem is, you don´t actually schedule a job class:
getScheduler().scheduleJob(new JobDetail("myFooJob", null, FooJob.class),
TriggerUtils.makeMinutelyTrigger("MIN_TRIGGER"));
full answer & demo code on http://www.codesmell.org/blog/2009/01/quartz-fits/
Do you really need scheduling, or just execution of repeating tasks at fixed intervals?
If the later, have a look at java build in ExecutorService, especially the ScheduledThreadPoolExecutor. Saves a whole framework for something quite simple :)