PDA

View Full Version : TimerFactoryBean and more than one tasks problem



davsclaus
Jan 12th, 2005, 03:13 AM
Hi

Scenario:
My use-case requires me to setup two Tasks after server startup.
Task A (scheduledTaskEDI) will loop forever and listen on an AS/400 dataqueue and process any incomming messages.
Task B (scheduledTaskTilmeldKunde) will do the same as A but listening to a different data queue.

I am using the build Spring support to setup my tasks and active the tasks after server startup using the TimerFactoryBean.

The problems is:
My 2nd task is never setup since the first task is never terminated (loop forever).

My configuration is:

<bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryB ean">
<property name="daemon">
<value>false</value>
</property>
<property name="scheduledTimerTasks">
<list>
<ref local="scheduledTaskTilmeldKunde"/>
<ref local="scheduledTaskEDI"/>
</list>
</property>
</bean>

<bean id="scheduledTaskTilmeldKunde" class="org.springframework.scheduling.timer.ScheduledTime rTask">
<property name="delay">
<value>10000</value>
</property>
<property name="period">
<value>-1</value>
</property>
<property name="timerTask">
<ref local="checkTilmeldKunde"/>
</property>
</bean>

<bean id="checkTilmeldKunde" class="org.springframework.scheduling.timer.MethodInvokin gTimerTaskFactoryBean">
<property name="targetObject">
<ref local="as400DataQueueTilmeldKunde"/>
</property>
<property name="targetMethod">
<value>listen</value>
</property>
</bean>

<bean id="checkFakturaEDI" class="org.springframework.scheduling.timer.MethodInvokin gTimerTaskFactoryBean">
<property name="targetObject">
<ref local="as400DataQueueEDI"/>
</property>
<property name="targetMethod">
<value>listen</value>
</property>
</bean>

<bean id="scheduledTaskEDI" class="org.springframework.scheduling.timer.ScheduledTime rTask">
<property name="delay">
<value>5000</value>
</property>
<property name="period">
<value>-1</value>
</property>
<property name="timerTask">
<ref local="checkFakturaEDI"/>
</property>
</bean>


And from my Tomcat log it can see that only the first job is started.


Thread-2 12 jan 2005 10&#58;01&#58;24 INFO dk.webfragt.access.as400.AS400DataQueueListener - DataQueueListener starting &#91;EDI&#93;
Thread-2 12 jan 2005 10&#58;01&#58;25 DEBUG dk.webfragt.access.as400.AS400DataQueueListener - Got AS/400 system
Thread-2 12 jan 2005 10&#58;01&#58;25 DEBUG dk.webfragt.access.as400.AS400DataQueueListener - Listening on data queue /QSYS.LIB/L2950TPGM.LIB/EBUDTAQ1.DTAQ, count=1


I have tried setting the deamon property of TimerFactoryBean to both true or false. But it never works.

If I change my code to terminate in the task instead of looping forever. Both jobs are started as the log below profs:


Thread-2 12 jan 2005 10&#58;09&#58;58 INFO dk.webfragt.access.as400.AS400DataQueueListener - DataQueueListener starting &#91;EDI&#93;
Thread-2 12 jan 2005 10&#58;10&#58;03 INFO dk.webfragt.access.as400.AS400DataQueueListener - DataQueueListener starting &#91;TilmeldKunde&#93;


I can see from the log above that both tasks are using the same thread Thread-2, but it could be the fact that the first job has terminated and thus Thread-2 is avail.

So what do you do to make sure that my 2 tasks are using their own thread?

davsclaus
Jan 12th, 2005, 03:42 AM
Okay I got it to work

I changed from using the Spring MethodInvokingTimerTaskFactoryBean to my own TimerTask object that spawns a new Thread.


public class AS400DataQueueListenerTimerTask extends TimerTask &#123;

public AS400DataQueueListener listener;

public void setListener&#40;AS400DataQueueListener listener&#41; &#123;
this.listener = listener;
&#125;

public void run&#40;&#41; &#123;
Job job = new Job&#40;listener&#41;;
new Thread&#40;job&#41;.start&#40;&#41;;
&#125;

/**
* To start the listener in its own thread.
*/
class Job implements Runnable &#123;

private AS400DataQueueListener listener;

public Job&#40;AS400DataQueueListener listener&#41; &#123;
this.listener = listener;
&#125;

public void run&#40;&#41; &#123;
listener.listen&#40;&#41;;
&#125;

&#125;

&#125;


Using this my two Tasks are started in their own thread, as the log shows:


Thread-14 12 jan 2005 10&#58;39&#58;27 INFO dk.webfragt.access.as400.AS400DataQueueListener - DataQueueListener starting &#91;EDI&#93;
Thread-14 12 jan 2005 10&#58;39&#58;27 DEBUG dk.webfragt.access.as400.AS400DataQueueListener - Got AS/400 system
Thread-14 12 jan 2005 10&#58;39&#58;27 DEBUG dk.webfragt.access.as400.AS400DataQueueListener - Listening on data queue /QSYS.LIB/L2950TPGM.LIB/EBUDTAQ1.DTAQ, count=1
Thread-15 12 jan 2005 10&#58;39&#58;32 INFO dk.webfragt.access.as400.AS400DataQueueListener - DataQueueListener starting &#91;TilmeldKunde&#93;
Thread-15 12 jan 2005 10&#58;39&#58;32 DEBUG dk.webfragt.access.as400.AS400DataQueueListener - Got AS/400 system
Thread-15 12 jan 2005 10&#58;39&#58;32 DEBUG dk.webfragt.access.as400.AS400DataQueueListener - Listening on data queue /QSYS.LIB/L2950TPGM.LIB/EBUDTAQ2.DTAQ, count=1

I would like to know if Spring actually have support for spawning a thread for the job to be executed?

Andreas Senft
Jan 12th, 2005, 04:08 AM
I would like to know if Spring actually have support for spawning a thread for the job to be executed?

Actually this problem arises from the Java Timer class used by Spring. This is from the documentation of java.util.Timer:


Corresponding to each Timer object is a single background thread that is used to execute all of the timer's tasks, sequentially. Timer tasks should complete quickly. If a timer task takes excessive time to complete, it "hogs" the timer's task execution thread.

So for your case I would suggest using a quartz-based timer.

Regards,
Andreas

davsclaus
Jan 12th, 2005, 05:10 AM
Thanks Andreas

I missed the part in the JDK javadoc - thanks.


I thought about changing to Quartz also but the JDK timer is very simple and I only needed the new features that Juergen added to the comming Spring 1.1.4 to set period = -1 to make it a one-shot-task instead of repeated execution. I recon that Quartz also have a feature to fire the job only once.

davsclaus
Jan 13th, 2005, 07:03 AM
Yes it works nicely with Quartz instead. Now I can avoid having my TimerTask classes that spawns their own new Thread.

For a one-shot execution job set both repeatCount and repeatInterval to 0.


<bean id="ediTrigger" class="org.springframework.scheduling.quartz.SimpleTrigge rBean">
<property name="jobDetail">
<ref local="checkFakturaEDITask" />
</property>
<property name="startDelay">
<!-- 10 seconds -->
<value>10000</value>
</property>
<property name="repeatInterval">
<value>0</value>
</property>
<property name="repeatCount">
<value>0</value>
</property>
</bean>