Repository: camel
Updated Branches:
  refs/heads/camel-2.13.x 62119f16d -> a69573424
  refs/heads/camel-2.14.x a0c8a5969 -> 31d384667


CAMEL-8076 We should avoid checking the DupTriggerKey if the recoverableJob is 
true


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/a6957342
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/a6957342
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/a6957342

Branch: refs/heads/camel-2.13.x
Commit: a69573424536fa3c307958cebdea0477b8df54c0
Parents: 62119f1
Author: Willem Jiang <willem.ji...@gmail.com>
Authored: Mon Nov 24 09:57:23 2014 +0800
Committer: Willem Jiang <willem.ji...@gmail.com>
Committed: Mon Nov 24 11:01:06 2014 +0800

----------------------------------------------------------------------
 .../camel/component/quartz2/QuartzEndpoint.java |  2 +-
 ...rtzConsumerTwoAppsClusteredRecoveryTest.java | 95 ++++++++++++++++++++
 ...ingQuartzConsumerRecoveryClusteredAppOne.xml | 77 ++++++++++++++++
 ...ingQuartzConsumerRecoveryClusteredAppTwo.xml | 72 +++++++++++++++
 4 files changed, 245 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/a6957342/components/camel-quartz2/src/main/java/org/apache/camel/component/quartz2/QuartzEndpoint.java
----------------------------------------------------------------------
diff --git 
a/components/camel-quartz2/src/main/java/org/apache/camel/component/quartz2/QuartzEndpoint.java
 
b/components/camel-quartz2/src/main/java/org/apache/camel/component/quartz2/QuartzEndpoint.java
index 9674aeb..3c9480a 100644
--- 
a/components/camel-quartz2/src/main/java/org/apache/camel/component/quartz2/QuartzEndpoint.java
+++ 
b/components/camel-quartz2/src/main/java/org/apache/camel/component/quartz2/QuartzEndpoint.java
@@ -227,7 +227,7 @@ public class QuartzEndpoint extends DefaultEndpoint {
         JobDetail jobDetail;
         Trigger oldTrigger = scheduler.getTrigger(triggerKey);
         boolean triggerExisted = oldTrigger != null;
-        if (triggerExisted) {
+        if (triggerExisted && !isRecoverableJob()) {
             ensureNoDupTriggerKey();
         }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a6957342/components/camel-quartz2/src/test/java/org/apache/camel/component/quartz2/SpringQuartzConsumerTwoAppsClusteredRecoveryTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-quartz2/src/test/java/org/apache/camel/component/quartz2/SpringQuartzConsumerTwoAppsClusteredRecoveryTest.java
 
b/components/camel-quartz2/src/test/java/org/apache/camel/component/quartz2/SpringQuartzConsumerTwoAppsClusteredRecoveryTest.java
new file mode 100644
index 0000000..4fe1ab9
--- /dev/null
+++ 
b/components/camel-quartz2/src/test/java/org/apache/camel/component/quartz2/SpringQuartzConsumerTwoAppsClusteredRecoveryTest.java
@@ -0,0 +1,95 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.quartz2;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Predicate;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.TestSupport;
+import org.apache.camel.util.IOHelper;
+import org.junit.Test;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * Tests a Quartz based cluster setup of two Camel Apps being triggered 
through with recoverableJob option is true {@link QuartzConsumer}.
+ * 
+ * @version
+ */
+public class SpringQuartzConsumerTwoAppsClusteredRecoveryTest extends 
TestSupport {
+
+    @Test
+    public void testQuartzPersistentStoreClusteredApp() throws Exception {
+        // boot up the database the two apps are going to share inside a 
clustered quartz setup
+        AbstractXmlApplicationContext db = new 
ClassPathXmlApplicationContext("org/apache/camel/component/quartz2/SpringQuartzConsumerClusteredAppDatabase.xml");
+        db.start();
+
+        // now launch the first clustered app which will acquire the quartz 
database lock and become the master
+        AbstractXmlApplicationContext app = new 
ClassPathXmlApplicationContext("org/apache/camel/component/quartz2/SpringQuartzConsumerRecoveryClusteredAppOne.xml");
+        app.start();
+
+        // as well as the second one which will run in slave mode as it will 
not be able to acquire the same lock
+        AbstractXmlApplicationContext app2 = new 
ClassPathXmlApplicationContext("org/apache/camel/component/quartz2/SpringQuartzConsumerRecoveryClusteredAppTwo.xml");
+        app2.start();
+
+        // now let's simulate a crash of the first app (the quartz instance 
'app-one')
+        log.warn("The first app is going to crash NOW!");
+        IOHelper.close(app);
+
+        log.warn("Crashed...");
+        log.warn("Crashed...");
+        log.warn("Crashed...");
+
+        // wait long enough until the second app takes it over...
+        Thread.sleep(20000);
+        // inside the logs one can then clearly see how the route of the 
second app ('app-two') starts consuming:
+        // 2013-09-30 11:22:20,349 [main           ] WARN  
erTwoAppsClusteredFailoverTest - Crashed...
+        // 2013-09-30 11:22:20,349 [main           ] WARN  
erTwoAppsClusteredFailoverTest - Crashed...
+        // 2013-09-30 11:22:20,349 [main           ] WARN  
erTwoAppsClusteredFailoverTest - Crashed...
+        // 2013-09-30 11:22:35,340 [_ClusterManager] INFO  
LocalDataSourceJobStore        - ClusterManager: detected 1 failed or restarted 
instances.
+        // 2013-09-30 11:22:35,340 [_ClusterManager] INFO  
LocalDataSourceJobStore        - ClusterManager: Scanning for instance 
"app-one"'s failed in-progress jobs.
+        // 2013-09-30 11:22:35,369 [eduler_Worker-1] INFO  triggered           
           - Exchange[ExchangePattern: InOnly, BodyType: String, Body: 
clustering PONGS!]
+
+        CamelContext camel2 = app2.getBean("camelContext2", 
CamelContext.class);
+
+        MockEndpoint mock2 = camel2.getEndpoint("mock:result", 
MockEndpoint.class);
+        mock2.expectedMinimumMessageCount(2);
+        mock2.expectedMessagesMatches(new ClusteringPredicate(false));
+
+        mock2.assertIsSatisfied();
+
+        // and as the last step shutdown the second app as well as the database
+        IOHelper.close(app2, db);
+    }
+    
+    private static class ClusteringPredicate implements Predicate {
+
+        private final String expectedPayload;
+        
+        ClusteringPredicate(boolean pings) {
+            expectedPayload = pings ? "clustering PINGS!" : "clustering 
PONGS!";
+        }
+        
+        @Override
+        public boolean matches(Exchange exchange) {
+            return exchange.getIn().getBody().equals(expectedPayload);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a6957342/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzConsumerRecoveryClusteredAppOne.xml
----------------------------------------------------------------------
diff --git 
a/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzConsumerRecoveryClusteredAppOne.xml
 
b/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzConsumerRecoveryClusteredAppOne.xml
new file mode 100644
index 0000000..a01b1c0
--- /dev/null
+++ 
b/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzConsumerRecoveryClusteredAppOne.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans";
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns:jdbc="http://www.springframework.org/schema/jdbc";
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://www.springframework.org/schema/jdbc 
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
+       http://camel.apache.org/schema/spring 
http://camel.apache.org/schema/spring/camel-spring.xsd";>
+
+  <bean id="quartzDataSource" class="org.apache.commons.dbcp.BasicDataSource">
+    <property name="driverClassName" 
value="org.apache.derby.jdbc.EmbeddedDriver" />
+    <!-- refer the embedded database we setup inside 
SpringQuartzConsumerClusteredAppDatabase.xml -->
+    <property name="url" value="jdbc:derby:memory:quartz-db" />
+    <property name="username" value="sa" />
+    <property name="password" value="" />
+  </bean>
+
+  <bean id="quartz2" 
class="org.apache.camel.component.quartz2.QuartzComponent">
+    <property name="scheduler" ref="scheduler"/>
+  </bean>
+
+  <bean id="scheduler" 
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
+    <property name="dataSource" ref="quartzDataSource"/>
+    <property name="autoStartup" value="false"/>
+    <property name="schedulerContextAsMap">
+      <!-- hook Camel into Quartz -->
+      <map>
+        <!-- CamelJob makes use of the following key below to find the same 
Job as we failover to 'app-two' -->
+        <!-- QuartzConstants.QUARTZ_CAMEL_CONTEXT + "-" + camelContextName  -->
+        <entry key="CamelQuartzCamelContext-camelContext" 
value-ref="camelContext"/>
+      </map>
+    </property>
+    <property name="quartzProperties">
+      <props>
+        <prop key="org.quartz.scheduler.instanceName">myscheduler</prop>
+        <prop key="org.quartz.scheduler.instanceId">app-one</prop>
+        <prop key="org.quartz.scheduler.skipUpdateCheck">true</prop>
+        <prop key="org.terracotta.quartz.skipUpdateCheck">true</prop>
+        <prop 
key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</prop>
+        <prop key="org.quartz.jobStore.isClustered">true</prop>
+        <prop key="org.quartz.jobStore.clusterCheckinInterval">5000</prop>
+      </props>
+    </property>
+  </bean>
+
+  <camelContext id="camelContext" shutdownEager="false" 
xmlns="http://camel.apache.org/schema/spring";>
+    <template id="template" />
+    <route id="myRoute">
+      <from 
uri="quartz2://app/test?trigger.repeatInterval=1000&amp;trigger.repeatCount=2&amp;durableJob=true&amp;stateful=true&amp;recoverableJob=true"
 />
+      <transform>
+        <simple>clustering PINGS!</simple>
+      </transform>
+      <to uri="log:triggered" />
+      <!--delay>
+         <constant>10000</constant>
+       </delay-->
+      <to uri="mock:result" />
+    </route>
+  </camelContext>
+
+</beans>

http://git-wip-us.apache.org/repos/asf/camel/blob/a6957342/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzConsumerRecoveryClusteredAppTwo.xml
----------------------------------------------------------------------
diff --git 
a/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzConsumerRecoveryClusteredAppTwo.xml
 
b/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzConsumerRecoveryClusteredAppTwo.xml
new file mode 100644
index 0000000..1672dab
--- /dev/null
+++ 
b/components/camel-quartz2/src/test/resources/org/apache/camel/component/quartz2/SpringQuartzConsumerRecoveryClusteredAppTwo.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans";
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns:jdbc="http://www.springframework.org/schema/jdbc";
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://www.springframework.org/schema/jdbc 
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
+       http://camel.apache.org/schema/spring 
http://camel.apache.org/schema/spring/camel-spring.xsd";>
+
+  <bean id="quartzDataSource" class="org.apache.commons.dbcp.BasicDataSource">
+    <property name="driverClassName" 
value="org.apache.derby.jdbc.EmbeddedDriver" />
+    <!-- refer the embedded database we setup inside 
SpringQuartzConsumerClusteredAppDatabase.xml -->
+    <property name="url" value="jdbc:derby:memory:quartz-db" />
+    <property name="username" value="sa" />
+    <property name="password" value="" />
+  </bean>
+
+  <bean id="quartz2" 
class="org.apache.camel.component.quartz2.QuartzComponent">
+    <property name="scheduler" ref="scheduler"/>
+  </bean>
+
+  <bean id="scheduler" 
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
+    <property name="dataSource" ref="quartzDataSource"/>
+    <property name="autoStartup" value="false"/>
+    <property name="schedulerContextAsMap">
+      <!-- hook Camel into Quartz -->
+      <map>
+        <entry key="CamelQuartzCamelContext-camelContext" 
value-ref="camelContext2"/>
+      </map>
+    </property>
+    <property name="quartzProperties">
+      <props>
+        <prop key="org.quartz.scheduler.instanceName">myscheduler</prop>
+        <prop key="org.quartz.scheduler.instanceId">app-two</prop>
+        <prop key="org.quartz.scheduler.skipUpdateCheck">true</prop>
+        <prop key="org.terracotta.quartz.skipUpdateCheck">true</prop>
+        <prop 
key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</prop>
+        <prop key="org.quartz.jobStore.isClustered">true</prop>
+        <prop key="org.quartz.jobStore.clusterCheckinInterval">5000</prop>
+      </props>
+    </property>
+  </bean>
+
+  <camelContext id="camelContext2" shutdownEager="true" 
xmlns="http://camel.apache.org/schema/spring";>
+    <template id="template" />
+    <route id="myRoute">
+      <from 
uri="quartz2://app/test?trigger.repeatInterval=1000&amp;trigger.repeatCount=2&amp;durableJob=true&amp;stateful=true&amp;recoverableJob=true"
 />
+      <transform>
+        <simple>clustering PONGS!</simple>
+      </transform>
+      <to uri="log:triggered" />
+      <to uri="mock:result" />
+    </route>
+  </camelContext>
+
+</beans>

Reply via email to