Aller au contenu | Aller au menu | Aller à la recherche


JBoss Scheduler & Quartz

Scheduler et Quartz avec Jboss, à la recherche d'un service de temps, permettant de paralléliser les processus lancés et à lancer.

Contrairement à ce que dit le post sur Jboss 6.1, il semble possible de paralléliser des processus.

Pour cela déjà 2 solutions sont fonctionnelles :

  • Schedulable
  • Quartz (et Job)

Schedulable

Dans votre implémentation de "org.jboss.varia.scheduler.Schedulable", il faudra définir la variable "TimerName", pour l'associer sur le timer par défaut, ou bien un autre timer (auto-créé si nouveau) pour que vos différents mbean de temps puissent se chevaucher (êtres lancés en parallèle).

com.placeoweb.schedul.MySchedulable.java
import java.util.Date;
 
import org.jboss.logging.Logger;
import org.jboss.varia.scheduler.Schedulable;
 
public class MySchedulable implements Schedulable {
 
	private final Logger logger = Logger.getLogger(this.getClass());
 
	public void perform(Date now, long remainingRepetitions) {
 
		System.out.println("DEBUT");
        logger.debug(this.getClass()+" SCHEDUL DEBUT "+new Date()+" (now:"+now+", remainingRepetitions:"+remainingRepetitions);
        try {
        	Thread.sleep(5000);
		} catch (InterruptedException e) {
			logger.fatal(this.getClass(),e);
		}
        logger.debug(this.getClass()+" SCHEDUL FIN "+new Date());
        System.out.println("FIN");
 
	}
 
}
META-INF/myscheduler-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<server>
 
<!--     java.lang.ClassNotFoundException: org.jboss.mx.timer.JBossTimer from BaseClassLoader -->
<!--     http://community.jboss.org/message/571539 -->
<!--     <mbean code="org.jboss.mx.timer.JBossTimer" => need to be replaced by "javax.management.timer.Timer" -->
<!--     <mbean code="javax.management.timer.Timer" -->
<!--            name="jboss:service=Timer2">  -->
<!--    	</mbean> -->
 
    <mbean code="org.jboss.varia.scheduler.Scheduler"
           name="MySchedulerTest:service=Scheduler">
        <attribute name="TimerName">jboss:service=TimerNew</attribute> <!-- Adding this attribute, is binding this scheduled class, on other independent timer service, so you can use parralels calls of yours SchedulableClass. Without using, is default binding on TimerName : jboss:service=Timer -->
        <attribute name="StartAtStartup">true</attribute>
        <attribute name="SchedulableClass">com.placeoweb.schedul.MySchedulable</attribute>
        <attribute name="InitialStartDate">NOW</attribute>
        <attribute name="SchedulePeriod">1000</attribute>
        <attribute name="InitialRepetitions">-1</attribute>
        <attribute name="FixedRate">true</attribute>
    </mbean>
 
    <mbean code="org.jboss.varia.scheduler.Scheduler"
           name="MySchedulerTest2:service=Scheduler">
        <attribute name="StartAtStartup">true</attribute>
        <attribute name="SchedulableClass">com.placeoweb.schedul.MySchedulable2</attribute>
        <attribute name="InitialStartDate">NOW</attribute>
        <attribute name="SchedulePeriod">1000</attribute>
        <attribute name="InitialRepetitions">-1</attribute>
        <attribute name="FixedRate">true</attribute>
    </mbean>    
 
</server>

Job et StatefulJob

Dans votre implémentation de "org.quartz.Job", il faudra plutôt implémenter "org.quartz.StatefulJob" pour définir une seule instance de votre mbean, ainsi, si la précédente exécution n'est pas terminée, on attends quelle se termine avant de relancer la suivante.

com.placeoweb.schedul.SimpleQuartzJob.java
import java.util.Date;
 
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;
 
//public class SimpleQuartzJob implements Job {
public class SimpleQuartzJob implements StatefulJob {
 
	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("In SimpleQuartzJob - executing its JOB at " 
                + new Date() + " by " + context.getTrigger().getName());
 
        try {
        	System.out.println("Waiting start");
			Thread.sleep(12000);
			System.out.println("Waiting stop");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
 
	}
 
}
META-INF/ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- <!DOCTYPE jboss PUBLIC "-//JBoss//DTD JBOSS 6.0//EN" "http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"> -->
<ejb-jar version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"  
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd">
 
	<enterprise-beans>
		<message-driven>
 
			<ejb-name>ExampleMDB</ejb-name>
	<!-- < ! - -    <ejb-class>org.jboss.tutorial.quartz.bean.QuartzMDBBean</ejb-class> - - >  -->
			<ejb-class>com.placeoweb.schedul.SimpleQuartzJob</ejb-class>
			<transaction-type>Container</transaction-type>
			<activation-config>
				<activation-config-property>
					<activation-config-property-name>cronTrigger</activation-config-property-name>
					<activation-config-property-value>0/2 * * * * ?</activation-config-property-value>
				</activation-config-property>
		   </activation-config>
		</message-driven>
 
		<message-driven>
 
			<ejb-name>ExampleMDB2</ejb-name>
	<!-- < ! - -    <ejb-class>org.jboss.tutorial.quartz.bean.QuartzMDBBean</ejb-class> - - >  -->
			<ejb-class>com.placeoweb.SimpleQuartzJob2</ejb-class>
			<transaction-type>Container</transaction-type>
			<activation-config>
				<activation-config-property>
					<activation-config-property-name>cronTrigger</activation-config-property-name>
					<activation-config-property-value>0/2 * * * * ?</activation-config-property-value>
				</activation-config-property>
		   </activation-config>
		</message-driven>
 
	</enterprise-beans>	
 
</ejb-jar>
META-INF\jboss.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss PUBLIC "-//JBoss//DTD JBOSS 6.0//EN" "http://www.jboss.org/j2ee/dtd/jboss_6_0.dtd">
<jboss>
	<enterprise-beans>
		<message-driven>
			<ejb-name>ExampleMDB</ejb-name>
			<resource-adapter-name>quartz-ra.rar</resource-adapter-name>
		</message-driven>
 
		<message-driven>
			<ejb-name>ExampleMDB2</ejb-name>
			<resource-adapter-name>quartz-ra.rar</resource-adapter-name>
		</message-driven>		
	</enterprise-beans>
</jboss>

Other way, with attributes names (without any file deployer like META-INF/ejb-jar.xml and META-INF\jboss.xml)

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
 
import org.jboss.ejb3.annotation.ResourceAdapter;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
 
// http://docs.jboss.org/ejb3/docs/tutorial/1.0.7/html/Quartz_scheduler_integration.html
// NOTE : Currently only cron jobs are allowed to be configured. 
 
@MessageDriven(activationConfig =
{@ActivationConfigProperty(propertyName = "cronTrigger", propertyValue = "*/10 * * * * ?")})	//	OK, génère une Java Class : org.jboss.ejb3.mdb.MessagingDelegateWrapper Description : Management Bean.
@ResourceAdapter("quartz-ra.rar")
public class TestQuartzJboss implements Job {
 
	@Override
	public void execute(JobExecutionContext arg0) throws JobExecutionException {
		System.out.println("HEllo de lu fron Quartz");
 
	}
 
}

Ressources

Jboss 6.1

boot.log d'un Jboss 6.1 et la section relative au lancement du service Quartz :

15:59:57,086 INFO  [AbstractServer] Starting: JBossAS [6.1.0.Final "Neo"]

16:00:28,086 INFO  [RARDeployment] Required license terms exist, view vfs:/C:/jboss-6.1.0.Final/server/default/deploy/quartz-ra.rar/META-INF/ra.xml
16:00:28,226 INFO  [SimpleThreadPool] Job execution threads will use class loader of thread: Thread-2
16:00:28,273 INFO  [SchedulerSignalerImpl] Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
16:00:28,273 INFO  [QuartzScheduler] Quartz Scheduler v.1.8.3 created.
16:00:28,273 INFO  [RAMJobStore] RAMJobStore initialized.
16:00:28,273 INFO  [QuartzScheduler] Scheduler meta-data: Quartz Scheduler (v1.8.3) 'JBossQuartzScheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.

16:00:28,273 INFO  [StdSchedulerFactory] Quartz scheduler 'JBossQuartzScheduler' initialized from an externally opened InputStream.
16:00:28,273 INFO  [StdSchedulerFactory] Quartz scheduler version: 1.8.3
16:00:28,273 INFO  [QuartzScheduler] Scheduler JBossQuartzScheduler_$_NON_CLUSTERED started.
mastertheboss.com - Application Server
Job scheduling with Quartz

Jobs and triggers

The two fundamental units of Quartz's scheduling package are jobs and triggers. A job is an executable task that can be scheduled, while a trigger provides a schedule for a job. While these two entities could easily have been combined, their separation in Quartz is both intentional and beneficial.

Les deux unités fondamentales du paquet d'ordonnancement de Quartz sont des emplois (jobs) et des déclencheurs (triggers). Un emploi est une tâche exécutable qui peut être prévue, alors qu'un déclencheur fournit un calendrier pour un emploi. Bien que ces deux entités auraient pu être facilement combinés, leur séparation en quartz est à la fois intentionnelle et bénéfique.

  • Exemple 1: Jobs
  • Exemple 2: Simple triggers
  • Exemple 3: Cron triggers
  • Job stores ( JDBCJobStore à la place du défaut RAMJobStore )
Using Quartz Scheduler in a Java web app (servlet)

You'll notice that i'm implementing StatefulJob instead of plain Job - this is so that if the job is still running when it is due to start again, Quartz won't start another instance of it:

//public class SimpleQuartzJob implements Job {
public class SimpleQuartzJob implements StatefulJob {
 
	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("In SimpleQuartzJob - executing its JOB at " 
                + new Date() + " by " + context.getTrigger().getName());
 
        try {
        	System.out.println("Waiting start");
			Thread.sleep(12000);
			System.out.println("Waiting stop");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
 
	}
 
}
Autre
Fichiers inclus avec JBoss 6.1

C:\jboss-6.1.0.Final\server\default\deploy\quartz-ra.rar\quartz-ra.jar\org\jboss\resource\adapter\quartz\inflow\quartz.properties

# Quartz configuration properties
org.quartz.scheduler.instanceName = JBossQuartzScheduler

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

# Don't check for new versions of quartz
org.quartz.scheduler.skipUpdateCheck = true

C:\jboss-6.1.0.Final\server\default\deploy\quartz-ra.rar\META-INF\ra.xml

<?xml version="1.0" encoding="UTF-8"?>
 
<!-- $Id: ra.xml 71556 2008-04-01 13:39:35Z adrian@jboss.org $ -->
 
<connector xmlns="http://java.sun.com/xml/ns/j2ee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
           http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"
           version="1.5">
 
   <description>Quartz Inflow Resource Adapter</description>
   <display-name>Quartz Adapter</display-name>
 
   <vendor-name>Red Hat Middleware LLC</vendor-name>
   <eis-type>Quartz Adapter</eis-type>
   <resourceadapter-version>5.0</resourceadapter-version>
 
   <license>
      <description>
 JBoss, Home of Professional Open Source.
 Copyright 2006, Red Hat Middleware LLC, and individual contributors
 as indicated by the @author tags. See the copyright.txt file in the
 distribution for a full listing of individual contributors.
 
 This is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as
 published by the Free Software Foundation; either version 2.1 of
 the License, or (at your option) any later version.
 
 This software is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public
 License along with this software; if not, write to the Free
 Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 02110-1301 USA, or see the FSF site: http://www.fsf.org.
      </description>
      <license-required>true</license-required>
   </license>
 
   <resourceadapter>
      <resourceadapter-class>org.jboss.resource.adapter.quartz.inflow.QuartzResourceAdapter</resourceadapter-class>
 
      <inbound-resourceadapter>
         <messageadapter>        
            <messagelistener>
               <messagelistener-type>org.quartz.Job</messagelistener-type>
               <activationspec>
                  <activationspec-class>org.jboss.resource.adapter.quartz.inflow.QuartzActivationSpec</activationspec-class>
                  <required-config-property>
                      <config-property-name>cronTrigger</config-property-name>
                  </required-config-property>
               </activationspec>
            </messagelistener>
            <messagelistener>
               <messagelistener-type>org.quartz.StatefulJob</messagelistener-type>
               <activationspec>
                  <activationspec-class>org.jboss.resource.adapter.quartz.inflow.QuartzActivationSpec</activationspec-class>
                  <required-config-property>
                      <config-property-name>cronTrigger</config-property-name>
                  </required-config-property>
               </activationspec>
            </messagelistener>
         </messageadapter>
      </inbound-resourceadapter>
 
   </resourceadapter>
</connector>