2012-07-19 10 views
7

Ich habe eine Feder Integrationsfluss durch den Cron-Ausdruck ausgelöst wie folgt:Federintegration + Cron + Quarz im Cluster?

<int-ftp:inbound-channel-adapter id="my-input-endpoint" ...> 
    <int:poller trigger="my-trigger"/> 
</int-ftp:inbound-channel-adapter> 

<bean id="my-trigger" 
    class="org.springframework.scheduling.support.CronTrigger"> 
    <constructor-arg value="0 * * * * *" /> 
</bean> 

Es funktioniert gut. Aber jetzt muss ich die Implementierung erweitern, um sie clusterfähig zu machen (Jobausführung auf nur einem Cluster-Knoten zum selben Zeitpunkt).

Mein Wunsch wäre, das Quartz-Framework im Cluster-Modus zu verwenden (den Auftragsstatus in der Datenbank beibehalten), um diesen Integrationsfluss auszulösen. Quarz bietet eine schöne Lösung aus der Box. Das einzige Problem ist, wie man den Quartz mit dem bestehenden Inbout-Channel-Adapter integriert? Das "Trigger" -Attribut des "Poller" akzeptiert nur die Unterklassen des org.springframework.scheduling.Trigger. Ich konnte keine Brücke zwischen "Poller-Trigger" und dem Quarz-Framework finden.

Vielen Dank im Voraus!

Antwort

6

Hier ist eine Art und Weise ...

das Auto-Start-Attribut für den Inbound-Adapter auf false gesetzt.

einen benutzerdefinierten Trigger erstellen, die nur einmal ausgelöst, sofort ...

public static class FireOnceTrigger implements Trigger { 

    boolean done; 

    public Date nextExecutionTime(TriggerContext triggerContext) { 
     if (done) { 
      return null; 
     } 
     done = true; 
     return new Date(); 
    } 

    public void reset() { 
     done = false; 
    } 
} 

In Ihrem Quarz Job, einen Verweis auf den Auslöser und die SourcePollingChannelAdapter bekommen.

Wenn die Quarz Trigger ausgelöst wird, haben die Quarz Job

  1. adapter.stop()
  2. trigger.reset()
  3. adapter.start()
+0

Falls jemand darauf stolpert - die Implementierung von Garys Lösung, zusammen mit einem Test zur Demonstration der Nutzung, finden Sie in [diesem Repo] (https://github.com/vpavic/spring-integration-quartz -Brücke). –

0

versucht zu integrieren der Quarz und die Feder, wie Sie vorgeschlagen haben, aber zwei andere Probleme konfrontiert:

1.) IncompatibleClassChangeError Ausnahme bei Verwendung von Quartz 2.x und Spring 3.x. Es ist ein bekanntes Problem, aber ich habe keine Lösung dafür gefunden.

2.) Injektion anderer Spring Bean in die Jobinstanz Quarz. Ich habe einige Lösungen gefunden, aber niemand arbeitet für mich. Ich habe die versucht man mit der Verwendung von

<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 
    <property name="jobFactory"> 
     <bean class="org.springframework.scheduling.quartz.SpringBeanJobFactory" /> 
    </property> 

    <property name="triggers"> 
     ... 
    </property> 

    <property name="schedulerContextAsMap"> 
     <map> 
      <entry key="inputEndpoint" value-ref="my-endpoint" /> 
     </map> 
    </property> 
</bean> 

anderen Bohnen in den Job zu injizieren, aber nach dieser Eigenschaft in die SchedulerFactoryBean Hinzufügen die Aufträge nicht ausgeführt werden (und ich nicht jede Ausnahme sehen). Durch das Entfernen der Eigenschaft "schedulerContextAsMap" wird der Job erneut ausgeführt.

+0

Temporäre Lösung für Problem 1) Downgrade der Quarz auf v1.8.5 2) meine Beobachtung: Wenn es Ausnahme während der Injektion von Beans aus dem Kontext zum Job mit der "SchedulerContextAsMap" -Methode (wie ClassCastException) gibt es keine Ausnahme von Spring Framework geworfen und kein Fehler protokolliert. Der Job wird gerade nicht gestartet. In meinem Fall habe ich erwartet, dass die Klasse des injizierten Eingangsendpunkts FtpInboundFileSynchronizingMessageSource wäre, das injizierte Objekt jedoch vom Typ SourcePollingChannelAdapter. – marc7

+0

Ja - Entschuldigung mein Tippfehler - behoben. –

2

die Lösung von Gary funktioniert.Das ist mein Frühling Kontext:

<int-ftp:inbound-channel-adapter id="my-endpoint" 
     auto-startup="false"> 
    <int:poller trigger="my-endpoint-trigger"/> 
</int-ftp:inbound-channel-adapter> 


<bean id="my-endpoint-trigger" class="com.my.FireOnceTrigger"/> 

<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 

    <property name="triggers"> 
     <list> 
      <ref bean="my-job-trigger" /> 
     </list> 
    </property> 

    <property name="schedulerContextAsMap"> 
     <map> 
      <entry key="inputEndpoint"><ref bean="my-input-endpoint" /></entry> 
      <entry key="inputEndpointTrigger"><ref bean="my-endpoint-trigger" /></entry> 
     </map> 
    </property> 
</bean> 

<bean id="my-job-trigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> 
    <property name="cronExpression" value="0 * * * * ?" /> 
    <property name="jobDetail" ref="my-job" /> 
</bean> 

<bean name="my-job" class="org.springframework.scheduling.quartz.JobDetailBean"> 
    <property name="jobClass" value="com.my.MyActivatorJob " /> 
</bean> 

und MyActivatorJob Klasse:

public class MyActivatorJob extends QuartzJobBean implements { 

private AbstractEndpoint inputEndpoint; 

private FireOnceTrigger inputEndpointTrigger; 

public void setInputEndpoint(final AbstractEndpoint pInputEndpoint) { 
    this.inputEndpoint = pInputEndpoint; 
} 

public void setInputEndpointTrigger(final FireOnceTrigger pInputEndpointTrigger) { 
    this.inputEndpointTrigger = pInputEndpointTrigger; 
} 

@Override 
protected void executeInternal(final JobExecutionContext pParamJobExecutionContext) 
throws JobExecutionException { 

    inputEndpoint.stop(); 
    inputEndpointTrigger.reset(); 
    inputEndpoint.start(); 
} 

}

Als nächster Schritt würde in diesem Frühjahr Zusammenhang die Verwendung von schedulerContextAsMap werden Refactoring müssen ersetzen mit etwas flexibler und in der Lage, mehr Jobs zu definieren, aktivieren und deaktivieren Sie viele verschiedene Endpunkte.

Danke Gary so weit!

+0

BTW, für jeden, der darüber stolpert: Quarz 2 arbeitet mit Spring 3, folgen Sie diesem Link: http://Stackoverflow.com/a/9866152/767530 –