You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by bv...@apache.org on 2013/09/25 00:29:35 UTC

git commit: CAMEL-6782: Added test demonstrating the failover of Camel routing inside a clustered quartz setup.

Updated Branches:
  refs/heads/master 88220b841 -> 8fb310682


CAMEL-6782: Added test demonstrating the failover of Camel routing inside a clustered quartz setup.

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

Branch: refs/heads/master
Commit: 8fb3106821d4f45b23d431cea95fd7622b6122d9
Parents: 88220b8
Author: Babak Vahdat <bv...@apache.org>
Authored: Wed Sep 25 00:29:24 2013 +0200
Committer: Babak Vahdat <bv...@apache.org>
Committed: Wed Sep 25 00:29:24 2013 +0200

----------------------------------------------------------------------
 .../quartz/ScheduledRoutePolicy.java            |  6 +-
 ...ngQuartzPersistentStoreClusteredAppTest.java | 85 ------------------
 ...pringQuartzTwoAppsClusteredFailoverTest.java | 94 ++++++++++++++++++++
 .../quartz/SpringQuartzClusteredAppOneTest.xml  | 26 +++---
 .../quartz/SpringQuartzClusteredAppTwoTest.xml  | 28 +++---
 .../quartz/SpringQuartzEmbeddedDatabase.xml     | 31 +++++++
 6 files changed, 155 insertions(+), 115 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/8fb31068/components/camel-quartz/src/main/java/org/apache/camel/routepolicy/quartz/ScheduledRoutePolicy.java
----------------------------------------------------------------------
diff --git a/components/camel-quartz/src/main/java/org/apache/camel/routepolicy/quartz/ScheduledRoutePolicy.java b/components/camel-quartz/src/main/java/org/apache/camel/routepolicy/quartz/ScheduledRoutePolicy.java
index 013bbb9..a22e397 100644
--- a/components/camel-quartz/src/main/java/org/apache/camel/routepolicy/quartz/ScheduledRoutePolicy.java
+++ b/components/camel-quartz/src/main/java/org/apache/camel/routepolicy/quartz/ScheduledRoutePolicy.java
@@ -90,11 +90,11 @@ public abstract class ScheduledRoutePolicy extends RoutePolicySupport implements
             JobDetail existingJobDetail = getScheduler().getJobDetail(jobDetail.getName(), jobDetail.getGroup());
             if (jobDetail.equals(existingJobDetail)) {
                 if (LOG.isInfoEnabled()) {
-                    LOG.info("Skipping to schedule the job: {} for action: {} on route {} as the job: {} already existing!",
+                    LOG.info("Skipping to schedule the job: {} for action: {} on route {} as the job: {} already existing inside the cluster",
                              new Object[] {jobDetail.getFullName(), action, route.getId(), existingJobDetail.getFullName()});
                 }
 
-                // skip scheduling the same job as one is already available for the same route and action
+                // skip scheduling the same job again as one is already existing for the same routeId and action
                 return;
             }
         }
@@ -150,7 +150,7 @@ public abstract class ScheduledRoutePolicy extends RoutePolicySupport implements
             getScheduler().deleteJob(jobDetailName, jobDetailGroup);
         }
 
-        LOG.debug("Scheduled Job: {}.{} is deleted", jobDetailGroup, jobDetailName);
+        LOG.debug("Scheduled job: {}.{} is deleted", jobDetailGroup, jobDetailName);
     }
     
     protected JobDetail createJobDetail(Action action, Route route) throws Exception {

http://git-wip-us.apache.org/repos/asf/camel/blob/8fb31068/components/camel-quartz/src/test/java/org/apache/camel/routepolicy/quartz/SpringQuartzPersistentStoreClusteredAppTest.java
----------------------------------------------------------------------
diff --git a/components/camel-quartz/src/test/java/org/apache/camel/routepolicy/quartz/SpringQuartzPersistentStoreClusteredAppTest.java b/components/camel-quartz/src/test/java/org/apache/camel/routepolicy/quartz/SpringQuartzPersistentStoreClusteredAppTest.java
deleted file mode 100644
index 26551cd..0000000
--- a/components/camel-quartz/src/test/java/org/apache/camel/routepolicy/quartz/SpringQuartzPersistentStoreClusteredAppTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * 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.routepolicy.quartz;
-
-import org.apache.camel.CamelContext;
-import org.apache.camel.CamelExecutionException;
-import org.apache.camel.ProducerTemplate;
-import org.apache.camel.component.direct.DirectConsumerNotAvailableException;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.test.junit4.TestSupport;
-
-import org.junit.Test;
-
-import org.springframework.context.support.AbstractXmlApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-/**
- * @version 
- */
-public class SpringQuartzPersistentStoreClusteredAppTest extends TestSupport {
-
-    @Test
-    public void testQuartzPersistentStoreClusteredApp() throws Exception {
-        // boot up the first clustered app which also launches an embedded database
-        AbstractXmlApplicationContext app = new ClassPathXmlApplicationContext("org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppOneTest.xml");
-        app.start();
-
-        // and now the second one
-        AbstractXmlApplicationContext app2 = new ClassPathXmlApplicationContext("org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppTwoTest.xml");
-        app2.start();
-
-        CamelContext camel = app.getBean("camelContext", CamelContext.class);
-        assertNotNull(camel);
-
-        MockEndpoint mock = camel.getEndpoint("mock:result", MockEndpoint.class);
-        mock.expectedMessageCount(1);
-        mock.expectedBodiesReceived("clustering pings!");
-
-        // wait a bit to make sure the route has been properly started through
-        // the given route policy
-        Thread.sleep(5000);
-
-        app.getBean("template", ProducerTemplate.class).sendBody("direct:start", "clustering");
-
-        mock.assertIsSatisfied();
-
-        CamelContext camel2 = app2.getBean("camelContext", CamelContext.class);
-        assertNotNull(camel2);
-
-        MockEndpoint mock2 = camel2.getEndpoint("mock:result", MockEndpoint.class);
-        mock2.expectedMessageCount(0);
-
-        // expect no consumer being started as the seconds app is expected to
-        // run in standby modus
-        try {
-            app2.getBean("template", ProducerTemplate.class).sendBody("direct:start", "clustering");
-            fail("Should have thrown exception");
-        } catch (CamelExecutionException cee) {
-            assertIsInstanceOf(DirectConsumerNotAvailableException.class, cee.getCause());
-        }
-
-        mock2.assertIsSatisfied();
-
-        // we're done so let's properly close the application contexts, but stop
-        // the second app before the first one so that the quartz scheduler running
-        // inside it can properly be shutdown
-        app2.close();
-        app.close();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/8fb31068/components/camel-quartz/src/test/java/org/apache/camel/routepolicy/quartz/SpringQuartzTwoAppsClusteredFailoverTest.java
----------------------------------------------------------------------
diff --git a/components/camel-quartz/src/test/java/org/apache/camel/routepolicy/quartz/SpringQuartzTwoAppsClusteredFailoverTest.java b/components/camel-quartz/src/test/java/org/apache/camel/routepolicy/quartz/SpringQuartzTwoAppsClusteredFailoverTest.java
new file mode 100644
index 0000000..84b67f6
--- /dev/null
+++ b/components/camel-quartz/src/test/java/org/apache/camel/routepolicy/quartz/SpringQuartzTwoAppsClusteredFailoverTest.java
@@ -0,0 +1,94 @@
+/**
+ * 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.routepolicy.quartz;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.TestSupport;
+import org.junit.Test;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * @version 
+ */
+public class SpringQuartzTwoAppsClusteredFailoverTest 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/routepolicy/quartz/SpringQuartzEmbeddedDatabase.xml");
+        db.start();
+
+        // now launch the first clustered app
+        AbstractXmlApplicationContext app = new ClassPathXmlApplicationContext("org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppOneTest.xml");
+        app.start();
+
+        // as well as the second one
+        AbstractXmlApplicationContext app2 = new ClassPathXmlApplicationContext("org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppTwoTest.xml");
+        app2.start();
+
+        CamelContext camel = app.getBean("camelContext", CamelContext.class);
+
+        MockEndpoint mock = camel.getEndpoint("mock:result", MockEndpoint.class);
+        mock.expectedMessageCount(1);
+        mock.expectedBodiesReceived("clustering PINGS!");
+
+        // wait a bit to make sure the route has already been properly started through the given route policy
+        Thread.sleep(5000);
+
+        app.getBean("template", ProducerTemplate.class).sendBody("direct:start", "clustering");
+
+        mock.assertIsSatisfied();
+
+        // now let's simulate a crash of the first app
+        log.warn("The first app is going to crash NOW!");
+        app.close();
+
+        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 CamelContext gets started:
+        // 2013-09-24 22:51:34,215 [main           ] WARN  ersistentStoreClusteredAppTest - Crashed...
+        // 2013-09-24 22:51:34,215 [main           ] WARN  ersistentStoreClusteredAppTest - Crashed...
+        // 2013-09-24 22:51:34,215 [main           ] WARN  ersistentStoreClusteredAppTest - Crashed...
+        // 2013-09-24 22:51:49,188 [_ClusterManager] INFO  LocalDataSourceJobStore        - ClusterManager: detected 1 failed or restarted instances.
+        // 2013-09-24 22:51:49,188 [_ClusterManager] INFO  LocalDataSourceJobStore        - ClusterManager: Scanning for instance "app-one"'s failed in-progress jobs.
+        // 2013-09-24 22:51:49,211 [eduler_Worker-1] INFO  SpringCamelContext             - Route: myRoute started and consuming from: Endpoint[direct://start]
+
+        CamelContext camel2 = app2.getBean("camelContext2", CamelContext.class);
+
+        MockEndpoint mock2 = camel2.getEndpoint("mock:result", MockEndpoint.class);
+        mock2.expectedMessageCount(1);
+        mock2.expectedBodiesReceived("clustering PONGS!");
+
+        app2.getBean("template", ProducerTemplate.class).sendBody("direct:start", "clustering");
+
+        mock2.assertIsSatisfied();
+
+        // stop the second app as we're already done
+        app2.close();
+
+        // and as the last step stop the database itself...
+        db.close();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/8fb31068/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppOneTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppOneTest.xml b/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppOneTest.xml
index d9584dc..75f7c05 100644
--- a/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppOneTest.xml
+++ b/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppOneTest.xml
@@ -21,23 +21,23 @@
        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
-    ">
+       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
 
-  <!-- the persistent store for quartz -->
-  <jdbc:embedded-database id="camel_quartz" type="DERBY">
-    <jdbc:script location="classpath:tables_derby.sql"/>
-  </jdbc:embedded-database>
+  <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 SpringQuartzEmbeddedDatabase.xml -->
+    <property name="url" value="jdbc:derby:memory:quartz-db" />
+    <property name="username" value="sa" />
+    <property name="password" value="" />
+  </bean>
 
   <bean id="quartz" class="org.apache.camel.component.quartz.QuartzComponent">
     <property name="scheduler" ref="scheduler"/>
   </bean>
 
-  <!-- jdbc:embedded-database must come before this so the job store exists -->
   <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
-    <property name="dataSource" ref="camel_quartz"/>
+    <property name="dataSource" ref="quartzDataSource"/>
     <property name="autoStartup" value="false"/>
-    <!-- let Camel start -->
     <property name="schedulerContextAsMap">
       <!-- hook Camel into Quartz -->
       <map>
@@ -47,11 +47,11 @@
     <property name="quartzProperties">
       <props>
         <prop key="org.quartz.scheduler.instanceName">myscheduler</prop>
-        <prop key="org.quartz.scheduler.instanceId">AUTO</prop>
+        <prop key="org.quartz.scheduler.instanceId">app-one</prop>
         <prop key="org.quartz.scheduler.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">1000</prop>
+        <prop key="org.quartz.jobStore.clusterCheckinInterval">5000</prop>
       </props>
     </property>
   </bean>
@@ -60,13 +60,13 @@
     <property name="routeStartTime" value="0/3 * * * * ?" />
   </bean>
 
-  <camelContext id="camelContext" managementNamePattern="#name#-#counter#" xmlns="http://camel.apache.org/schema/spring">
+  <camelContext id="camelContext" managementNamePattern="#name#" xmlns="http://camel.apache.org/schema/spring">
     <template id="template" />
     <route id="myRoute" routePolicyRef="startPolicy" autoStartup="false">
       <from uri="direct:start" />
       <to uri="log:triggered" />
       <transform>
-        <simple>${in.body} pings!</simple>
+        <simple>${body} PINGS!</simple>
       </transform>
       <to uri="mock:result" />
     </route>

http://git-wip-us.apache.org/repos/asf/camel/blob/8fb31068/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppTwoTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppTwoTest.xml b/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppTwoTest.xml
index b09dd44..6126464 100644
--- a/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppTwoTest.xml
+++ b/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzClusteredAppTwoTest.xml
@@ -21,37 +21,37 @@
        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
-    ">
+       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
 
-  <!-- the persistent store for quartz -->
-  <jdbc:embedded-database id="camel_quartz" type="DERBY">
-    <!-- do not load script as database alreaady exists -->
-  </jdbc:embedded-database>
+  <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 SpringQuartzEmbeddedDatabase.xml -->
+    <property name="url" value="jdbc:derby:memory:quartz-db" />
+    <property name="username" value="sa" />
+    <property name="password" value="" />
+  </bean>
 
   <bean id="quartz" class="org.apache.camel.component.quartz.QuartzComponent">
     <property name="scheduler" ref="scheduler"/>
   </bean>
 
-  <!-- jdbc:embedded-database must come before this so the job store exists -->
   <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
-    <property name="dataSource" ref="camel_quartz"/>
+    <property name="dataSource" ref="quartzDataSource"/>
     <property name="autoStartup" value="false"/>
-    <!-- let Camel start -->
     <property name="schedulerContextAsMap">
       <!-- hook Camel into Quartz -->
       <map>
-        <entry key="CamelQuartzCamelContext" value-ref="camelContext"/>
+        <entry key="CamelQuartzCamelContext" value-ref="camelContext2"/>
       </map>
     </property>
     <property name="quartzProperties">
       <props>
         <prop key="org.quartz.scheduler.instanceName">myscheduler</prop>
-        <prop key="org.quartz.scheduler.instanceId">AUTO</prop>
+        <prop key="org.quartz.scheduler.instanceId">app-two</prop>
         <prop key="org.quartz.scheduler.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">1000</prop>
+        <prop key="org.quartz.jobStore.clusterCheckinInterval">5000</prop>
       </props>
     </property>
   </bean>
@@ -60,13 +60,13 @@
     <property name="routeStartTime" value="0/3 * * * * ?" />
   </bean>
 
-  <camelContext id="camelContext" managementNamePattern="#name#-#counter#" xmlns="http://camel.apache.org/schema/spring">
+  <camelContext id="camelContext2" managementNamePattern="#name#" xmlns="http://camel.apache.org/schema/spring">
     <template id="template" />
     <route id="myRoute" routePolicyRef="startPolicy" autoStartup="false">
       <from uri="direct:start" />
       <to uri="log:triggered" />
       <transform>
-        <simple>${in.body} pongs!</simple>
+        <simple>${body} PONGS!</simple>
       </transform>
       <to uri="mock:result" />
     </route>

http://git-wip-us.apache.org/repos/asf/camel/blob/8fb31068/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzEmbeddedDatabase.xml
----------------------------------------------------------------------
diff --git a/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzEmbeddedDatabase.xml b/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzEmbeddedDatabase.xml
new file mode 100644
index 0000000..83ae9c6
--- /dev/null
+++ b/components/camel-quartz/src/test/resources/org/apache/camel/routepolicy/quartz/SpringQuartzEmbeddedDatabase.xml
@@ -0,0 +1,31 @@
+<?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">
+
+  <!-- the embedded persistent storage for quartz -->
+  <jdbc:embedded-database id="quartz-db" type="DERBY">
+    <jdbc:script location="classpath:tables_derby.sql"/>
+  </jdbc:embedded-database>
+
+</beans>