PDA

View Full Version : Create Quartz Jobs as Prototypes



rpepersack
Mar 3rd, 2008, 08:56 AM
Hello.

I would like to configure Spring so that it creates a new Quartz job instance every time a trigger fires (i.e. prototype instead of singleton). I'm using MethodInvokingJobDetailFactoryBean, CronTriggerBean, and SchedulerFactoryBean. I've looked in the forum, the API, and the code, but I couldn't find an example that demonstrates this. Does anyone know how to get Spring do this, or if it's possible?

Thank you!

Alarmnummer
Mar 3rd, 2008, 09:11 AM
What is the reason you want this behavior?

rpepersack
Mar 3rd, 2008, 09:22 AM
I want to make sure that my jobs are thread-safe, as Quartz ensures, and set Spring so that the second job will not have to wait until first job has finished, as does the "concurrent" property of MethodInvokingJobDetailFactoryBean.

Alarmnummer
Mar 3rd, 2008, 09:25 AM
I want to make sure that my jobs are thread-safe, as Quartz ensures, and set Spring so that the second job will not have to wait until first job has finished, as does the "concurrent" property of MethodInvokingJobDetailFactoryBean.
I don't understand what you want.

So by creating multiple jobs (each job executed by a different thread) you want to make it threadsafe? (isolation/confinement is a very valuable technique for concurrency control). But do you jobs have state?

Personally I prefer making quartz (or any other threading engine) as stupid as possible. If I need to maintain some kind of context(state) for a Job, I make it part of the call.



class FireService{
void fireThemAll(){
FireThemAllContext context = new FireThemAllContext();
... now pass the context to the locations needed (could also use a threadlocal for this but making it explicit is less vague).
}
}


And now the FireService.fireThemAll Service can be called by the same instance of the QuartzJob (MethodInvoking.... for example) by multiple Quartz-threads.

rpepersack
Mar 3rd, 2008, 09:44 AM
Yes, my jobs have state. Some also take a long time to finish. That's why I want each job to have its own instance. I'm new to Spring, so please bear with me. Are you suggesting that I should create a factory class that creates a new Job instance?

Alarmnummer
Mar 3rd, 2008, 09:50 AM
Yes, my jobs have state. Some also take a long time to finish. That's why I want each job to have its own instance. I'm new to Spring, so please bear with me. Are you suggesting that I should create a factory class that creates a new Job instance?
Nope.. suggest that you make the calling context (a location where you can store state) part of your design. See the example I have provided.

If you make it part of your design, you don't need to add this logic to the QuartzJob..

In essence you are moving the responsibility of creating 'a context per thread' from quarts to your service. Maybe the name context is a little bit confusing; maybe it would be better to call it job (the job contains the context of the call).



class FireService{
void fireAll(){
FireAllJob job = new FireAllJob();
job.setStartTime(new Date()); //some data specific to this call
... now do calls and you can pass the job to these calls.
}
}

rpepersack
Mar 3rd, 2008, 11:50 AM
So, would I configure my Spring XML file so that all of my job details would call FireService, which would, in turn, call FireAllJob? Would FireAllJob create instances of my jobs, or is it just for storing state?

Alarmnummer
Mar 4th, 2008, 02:54 AM
So, would I configure my Spring XML file so that all of my job details would call FireService

Correct.

You just need to hook up a Quartz scheduler (or any other mechanism) to that fire method of the FireService.



which would, in turn, call FireAllJob?

Correct.



Would FireAllJob create instances of my jobs, or is it just for storing state?
The FireAllJob is the Job you are executing. So I don't think you need to create additional jobs (unless you are splitting up the FireAllJob in smaller Jobs.. but that depends on the situation again).

rpepersack
Mar 4th, 2008, 07:29 AM
I assume that the "service class" would be a singleton, and the jobs would be prototypes. If my "service" class acts as a "job instance creator", then how do I tell it which job to create? Or, does each "job prototype" have its own "singleton creator"?

Alarmnummer
Mar 4th, 2008, 07:45 AM
I assume that the "service class" would be a singleton, and the jobs would be prototypes.

Correct :)



If my "service" class acts as a "job instance creator", then how do I tell it which job to create? Or, does each "job prototype" have its own "singleton creator"?
That depends on your requirements/taste. I don't know anything about the requirements to help you in a good direction. I don't know how complex the tasks are.. if logic should be added to the job... or if the job should be a 'state container'.. it all depends. There are many different ways to design it.

rpepersack
Mar 4th, 2008, 08:53 AM
I have several different jobs. I would like to create a single service class that can create an instance of whichever job I need, when the job's trigger fires. I know how to create classes using design patterns. It sounds like the service class can follow the Factory Method pattern. So, assuming that I create a "job factory singleton bean" class, how would I get Spring IOC tell it which job to create and run when a trigger fires?

Alarmnummer
Mar 5th, 2008, 09:26 AM
Each trigger, could call a different method on a service. And each service method can create a different job.



class SomeService{

void foo(){
FooJob job = new FooJob(...);
....
}

void bar(){
BarJob job = new BarJob(...);
...
}
}

rpepersack
Mar 5th, 2008, 09:48 AM
I like it. Short and sweet, but I have more questions.

If I create my jobs with the "new" operator (e.g. FooJob job = new FooJob()), then how would I get the Spring IOC container to inject the dependencies into FooJob and BarJob? For example, FooJob needs FooDao injected into it.

Also, would I inject SomeService into the "targetObject" property of MethodInvokingJobDetailFactoryBean? This seems a little cumbersome, so is there a better way?

Thanks.

Alarmnummer
Mar 5th, 2008, 10:13 AM
If I create my jobs with the "new" operator (e.g. FooJob job = new FooJob()), then how would I get the Spring IOC container to inject the dependencies into FooJob and BarJob? For example, FooJob needs FooDao injected into it.

It depends on the situation. If there are not resources, I inject them in the Service and when the job is created, the service can inject them in the Job. If there are more dependencies, I create a Factory..



void foo(){
FooJob job = fooJobFactory.create();
....
}




Also, would I inject SomeService into the "targetObject" property of MethodInvokingJobDetailFactoryBean? This seems a little cumbersome, so is there a better way?

Why is it cumbersome (apart from the large amount of XML stuff).



<!-- A Trigger for the fileSystemMontitor -->
<bean id="fileSystemMonitorTrigger"
class="org.springframework.scheduling.quartz.CronTriggerB ean">
<property name="jobDetail">
<bean class="org.springframework.scheduling.quartz.MethodInvoki ngJobDetailFactoryBean">
<property name="targetObject"
ref="fileSystemMonitor"/>
<property name="targetMethod"
value="check"/>
<!-- we don't want concurrent executions-->
<property name="concurrent"
value="false"/>
</bean>
</property>
<property name="cronExpression"
value="${intake.uploadDirectoryCronExpression}"/>
</bean>

<!-- the scheduler that triggers the FileSystemMonitor -->
<bean id="fileSystemMonitorScheduler"
class="org.springframework.scheduling.quartz.SchedulerFac toryBean">
<property name="quartzProperties">
<props>
<prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
<prop key="org.quartz.threadPool.threadCount">1</prop>
<prop key="org.quartz.threadPool.threadPriority">1</prop>
</props>
</property>

<property name="triggers">
<list>
<ref bean="fileSystemMonitorTrigger"/>
</list>
</property>
</bean>

erezmazor
Jun 26th, 2010, 12:47 AM
You could also use ObjectFactoryCreatingFactoryBean (http://techo-ecco.com/blog/quartz-and-spring-integration/) for that

erezmazor
Jul 17th, 2011, 07:19 AM
This post (http://techo-ecco.com/blog/quartz-and-spring-integration/) shows how to use prototype-scoped Quartz Triggers and JobDetails with Spring via the use of ObjectFactoryCreatingFactoryBean (http://static.springsource.org/spring/docs/current/api/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.html)