You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/07/02 09:04:50 UTC

[camel] branch camel-2.24.x updated: CAMEL-13466: CamelContext should stop routes which failed to start when Camel is shutting down. This is to ensure resources leaks etc from those failed routes are also stopped, eg in karaf or app servers to have all resources stopped when you undeploy. Thanks to Julien Greffe for reporting and a prototype fix and to Jean Baptiste for working on a PR.

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch camel-2.24.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-2.24.x by this push:
     new 9710034  CAMEL-13466: CamelContext should stop routes which failed to start when Camel is shutting down. This is to ensure resources leaks etc from those failed routes are also stopped, eg in karaf or app servers to have all resources stopped when you undeploy. Thanks to Julien Greffe for reporting and a prototype fix and to Jean Baptiste for working on a PR.
9710034 is described below

commit 971003446d133fe2cb697a7d1f00f7223dcab084
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Jul 2 10:48:48 2019 +0200

    CAMEL-13466: CamelContext should stop routes which failed to start when Camel is shutting down. This is to ensure resources leaks etc from those failed routes are also stopped, eg in karaf or app servers to have all resources stopped when you undeploy. Thanks to Julien Greffe for reporting and a prototype fix and to Jean Baptiste for working on a PR.
---
 .../org/apache/camel/impl/DefaultCamelContext.java |  15 ++-
 .../RouteStartupFailShouldStopAlsoIssueTest.java   | 142 +++++++++++++++++++++
 2 files changed, 150 insertions(+), 7 deletions(-)

diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
index 69670f0..4660c6c 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
@@ -43,7 +43,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
-
 import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
 import javax.naming.Context;
@@ -3510,13 +3509,15 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon
         // shutdown await manager to trigger interrupt of blocked threads to attempt to free these threads graceful
         shutdownServices(asyncProcessorAwaitManager);
 
-        routeStartupOrder.sort(new Comparator<RouteStartupOrder>() {
-            @Override
-            public int compare(RouteStartupOrder o1, RouteStartupOrder o2) {
-                // Reversed order
-                return Integer.compare(o2.getStartupOrder(), o1.getStartupOrder());
+        // we ned also to include routes which failed to start to ensure all resources get stopped when stopping Camel
+        for (RouteService routeService : routeServices.values()) {
+            boolean found = routeStartupOrder.stream().anyMatch(o -> o.getRoute().getId().equals(routeService.getId()));
+            if (!found) {
+                log.debug("Route: {} which failed to startup will be stopped", routeService.getId());
+                routeStartupOrder.add(doPrepareRouteToBeStarted(routeService));
             }
-        });
+        }
+        routeStartupOrder.sort(Comparator.comparingInt(RouteStartupOrder::getStartupOrder).reversed());
         List<RouteService> list = new ArrayList<>();
         for (RouteStartupOrder startupOrder : routeStartupOrder) {
             DefaultRouteStartupOrder order = (DefaultRouteStartupOrder) startupOrder;
diff --git a/camel-core/src/test/java/org/apache/camel/issues/RouteStartupFailShouldStopAlsoIssueTest.java b/camel-core/src/test/java/org/apache/camel/issues/RouteStartupFailShouldStopAlsoIssueTest.java
new file mode 100644
index 0000000..7875e31
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/issues/RouteStartupFailShouldStopAlsoIssueTest.java
@@ -0,0 +1,142 @@
+/**
+ * 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.issues;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.Consumer;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.impl.DefaultConsumer;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.junit.Test;
+
+public class RouteStartupFailShouldStopAlsoIssueTest extends ContextTestSupport {
+
+    private static final List<String> EVENTS = new ArrayList<>();
+
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
+
+    @Test
+    public void testShouldAlsoStop() throws Exception {
+        context.addComponent("my", new MyComponent(context));
+
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:bar").routeId("bar")
+                        .to("mock:bar");
+
+                // the foo route fails to startup but it should be stopped when camel stops
+                from("my:foo").routeId("foo")
+                        .to("mock:foo");
+            }
+        });
+
+        try {
+            context.start();
+        } catch (Exception e) {
+            // should fail
+        }
+
+        assertTrue(context.getRouteStatus("foo").isStopped());
+        assertFalse(context.getRouteStatus("foo").isStarted());
+
+        assertTrue(context.getRouteStatus("bar").isStopped());
+        assertFalse(context.getRouteStatus("bar").isStarted());
+
+        context.stop();
+
+        assertTrue(context.getRouteStatus("foo").isStopped());
+        assertFalse(context.getRouteStatus("foo").isStarted());
+
+        assertTrue(context.getRouteStatus("bar").isStopped());
+        assertFalse(context.getRouteStatus("bar").isStarted());
+
+        assertEquals(3, EVENTS.size());
+        assertEquals("constructor", EVENTS.get(0));
+        assertEquals("doStart", EVENTS.get(1));
+        assertEquals("doStop", EVENTS.get(2));
+    }
+
+    private class MyComponent extends DefaultComponent {
+
+        public MyComponent(CamelContext context) {
+            super(context);
+        }
+
+        @Override
+        protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+            return new MyEndpoint(uri, this);
+        }
+    }
+
+    private class MyEndpoint extends DefaultEndpoint {
+
+        public MyEndpoint(String endpointUri, Component component) {
+            super(endpointUri, component);
+        }
+
+        @Override
+        public Producer createProducer() throws Exception {
+            throw new UnsupportedOperationException("Not supported");
+        }
+
+        @Override
+        public Consumer createConsumer(Processor processor) throws Exception {
+            return new MyFailConsumer(this, processor);
+        }
+
+        @Override
+        public boolean isSingleton() {
+            return true;
+        }
+    }
+
+    private class MyFailConsumer extends DefaultConsumer {
+
+        public MyFailConsumer(Endpoint endpoint, Processor processor) {
+            super(endpoint, processor);
+            EVENTS.add("constructor");
+        }
+
+        @Override
+        protected void doStart() throws Exception {
+            super.doStart();
+            EVENTS.add("doStart");
+            throw new IllegalStateException("Forced failure");
+        }
+
+        @Override
+        protected void doStop() throws Exception {
+            super.doStop();
+            EVENTS.add("doStop");
+        }
+    }
+
+}