CAMEL-11640: SupervisingRouteController : Add a SPI to filter routes to supervise
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/2b832e93 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/2b832e93 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/2b832e93 Branch: refs/heads/master Commit: 2b832e937e0a1cdd3a8037880a90d0261b0f4804 Parents: ef5aa1f Author: lburgazzoli <lburgazz...@gmail.com> Authored: Mon Aug 7 12:04:27 2017 +0200 Committer: lburgazzoli <lburgazz...@gmail.com> Committed: Tue Aug 8 13:29:29 2017 +0200 ---------------------------------------------------------------------- .../apache/camel/impl/DefaultCamelContext.java | 2 +- .../camel/impl/DefaultRouteController.java | 12 ++-- .../camel/impl/SupervisingRouteController.java | 75 +++++++++++++++++++- .../impl/SupervisingRouteControllerFilters.java | 51 +++++++++++++ .../org/apache/camel/spi/RouteController.java | 15 ++-- ...rvisingRouteControllerAutoConfiguration.java | 25 +++++-- ...SupervisingRouteControllerConfiguration.java | 13 ++++ .../java/sample/camel/ApplicationRoutes.java | 8 ++- .../src/main/resources/application.properties | 4 +- 9 files changed, 177 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/2b832e93/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java ---------------------------------------------------------------------- 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 1856ebd..61939b8 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 @@ -3171,7 +3171,7 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon } } - final List<Route> controlledRoutes = getRouteController().getControlledRoutes(); + final Collection<Route> controlledRoutes = getRouteController().getControlledRoutes(); if (controlledRoutes.isEmpty()) { log.info("Total {} routes, of which {} are started", http://git-wip-us.apache.org/repos/asf/camel/blob/2b832e93/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteController.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteController.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteController.java index db10a33..6d46adc 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteController.java +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteController.java @@ -16,9 +16,8 @@ */ package org.apache.camel.impl; -import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; -import java.util.List; import java.util.concurrent.TimeUnit; import org.apache.camel.CamelContext; @@ -28,16 +27,13 @@ import org.apache.camel.spi.RouteController; @Experimental public class DefaultRouteController extends org.apache.camel.support.ServiceSupport implements RouteController { - private final List<Route> routes; private CamelContext camelContext; - public DefaultRouteController() { this(null); } public DefaultRouteController(CamelContext camelContext) { this.camelContext = camelContext; - this.routes = new ArrayList<>(); } // *************************************************** @@ -105,8 +101,12 @@ public class DefaultRouteController extends org.apache.camel.support.ServiceSupp camelContext.resumeRoute(routeId); } + // *************************************************** + // + // *************************************************** + @Override - public List<Route> getControlledRoutes() { + public Collection<Route> getControlledRoutes() { return Collections.emptyList(); } } http://git-wip-us.apache.org/repos/asf/camel/blob/2b832e93/camel-core/src/main/java/org/apache/camel/impl/SupervisingRouteController.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/SupervisingRouteController.java b/camel-core/src/main/java/org/apache/camel/impl/SupervisingRouteController.java index 8e5167e..3054ac4 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/SupervisingRouteController.java +++ b/camel-core/src/main/java/org/apache/camel/impl/SupervisingRouteController.java @@ -17,6 +17,9 @@ package org.apache.camel.impl; import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.EventObject; import java.util.HashMap; import java.util.List; @@ -31,6 +34,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; import java.util.stream.Collectors; import org.apache.camel.CamelContext; @@ -48,6 +52,7 @@ import org.apache.camel.spi.RouteController; import org.apache.camel.spi.RoutePolicy; import org.apache.camel.spi.RoutePolicyFactory; import org.apache.camel.support.EventNotifierSupport; +import org.apache.camel.util.CamelContextHelper; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.backoff.BackOff; import org.apache.camel.util.backoff.BackOffContext; @@ -68,6 +73,7 @@ public class SupervisingRouteController extends DefaultRouteController { private final Object lock; private final AtomicBoolean contextStarted; private final AtomicInteger routeCount; + private final List<Filter> filters; private final Set<RouteHolder> routes; private final CamelContextStartupListener listener; private final RouteManager routeManager; @@ -80,6 +86,7 @@ public class SupervisingRouteController extends DefaultRouteController { public SupervisingRouteController() { this.lock = new Object(); this.contextStarted = new AtomicBoolean(false); + this.filters = new ArrayList<>(); this.routeCount = new AtomicInteger(0); this.routes = new TreeSet<>(); this.routeManager = new RouteManager(); @@ -166,6 +173,25 @@ public class SupervisingRouteController extends DefaultRouteController { this.initialDelay = Duration.ofMillis(initialDelay); } + /** + * Add a filter used to determine the routes to supervise. + */ + public void addFilter(Filter filter) { + this.filters.add(filter); + } + + /** + * Sets the filters user to determine the routes to supervise. + */ + public void setFilters(Collection<Filter> filters) { + this.filters.clear(); + this.filters.addAll(filters); + } + + public Collection<Filter> getFilters() { + return Collections.unmodifiableList(filters); + } + // ********************************* // Lifecycle // ********************************* @@ -298,7 +324,7 @@ public class SupervisingRouteController extends DefaultRouteController { } @Override - public List<Route> getControlledRoutes() { + public Collection<Route> getControlledRoutes() { return routes.stream() .map(RouteHolder::get) .collect(Collectors.toList()); @@ -596,11 +622,21 @@ public class SupervisingRouteController extends DefaultRouteController { @Override public void onInit(Route route) { - if ("false".equals(route.getRouteContext().getRoute().getAutoStartup())) { - LOGGER.info("Route {} has explicit auto-startup flag set to false, ignore it", route.getId()); + final String autoStartup = route.getRouteContext().getRoute().getAutoStartup(); + if (ObjectHelper.equalIgnoreCase("false", autoStartup)) { + LOGGER.info("Route {} won't be supervised (reason: has explicit auto-startup flag set to false)", route.getId()); return; } + for (Filter filter : filters) { + FilterResult result = filter.apply(route); + + if (!result.supervised()) { + LOGGER.info("Route {} won't be supervised (reason: {})", route.getId(), result.reason()); + return; + } + } + RouteHolder holder = new RouteHolder(route, routeCount.incrementAndGet()); if (routes.add(holder)) { holder.getContext().setRouteController(SupervisingRouteController.this); @@ -702,4 +738,37 @@ public class SupervisingRouteController extends DefaultRouteController { } } } + + // ********************************* + // Filter + // ********************************* + + @Experimental + public static class FilterResult { + public static final FilterResult SUPERVISED = new FilterResult(true, null); + + private final boolean controlled; + private final String reason; + + public FilterResult(boolean controlled, String reason) { + this.controlled = controlled; + this.reason = reason; + } + + public FilterResult(boolean controlled, String format, Object... args) { + this(controlled, String.format(format, args)); + } + + public boolean supervised() { + return controlled; + } + + public String reason() { + return reason; + } + } + + @Experimental + public interface Filter extends Function<Route, FilterResult> { + } } http://git-wip-us.apache.org/repos/asf/camel/blob/2b832e93/camel-core/src/main/java/org/apache/camel/impl/SupervisingRouteControllerFilters.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/SupervisingRouteControllerFilters.java b/camel-core/src/main/java/org/apache/camel/impl/SupervisingRouteControllerFilters.java new file mode 100644 index 0000000..43ecd6a --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/impl/SupervisingRouteControllerFilters.java @@ -0,0 +1,51 @@ +/** + * 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.impl; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.apache.camel.Route; + +public final class SupervisingRouteControllerFilters { + private SupervisingRouteControllerFilters() { + } + + public static final class BlackList implements SupervisingRouteController.Filter { + private final Set<String> names; + + public BlackList(String name) { + this(Collections.singletonList(name)); + } + + public BlackList(Collection<String> names) { + this.names = new HashSet<>(names); + } + + @Override + public SupervisingRouteController.FilterResult apply(Route route) { + boolean supervised = !names.contains(route.getId()); + + return new SupervisingRouteController.FilterResult( + supervised, + supervised ? null : "black-listed" + ); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/2b832e93/camel-core/src/main/java/org/apache/camel/spi/RouteController.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/spi/RouteController.java b/camel-core/src/main/java/org/apache/camel/spi/RouteController.java index 0e55c52..d19a8a2 100644 --- a/camel-core/src/main/java/org/apache/camel/spi/RouteController.java +++ b/camel-core/src/main/java/org/apache/camel/spi/RouteController.java @@ -16,7 +16,7 @@ */ package org.apache.camel.spi; -import java.util.List; +import java.util.Collection; import java.util.concurrent.TimeUnit; import org.apache.camel.CamelContextAware; @@ -26,6 +26,12 @@ import org.apache.camel.Service; @Experimental public interface RouteController extends CamelContextAware, Service { + /** + * Return the list of routes controlled by this controller. + * + * @return the list of controlled routes; + */ + Collection<Route> getControlledRoutes(); void startRoute(String routeId) throws Exception; @@ -40,11 +46,4 @@ public interface RouteController extends CamelContextAware, Service { void suspendRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception; void resumeRoute(String routeId) throws Exception; - - /** - * Return the list of routes controlled by this controller. - * - * @return the list of controlled routes; - */ - List<Route> getControlledRoutes(); } http://git-wip-us.apache.org/repos/asf/camel/blob/2b832e93/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SupervisingRouteControllerAutoConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SupervisingRouteControllerAutoConfiguration.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SupervisingRouteControllerAutoConfiguration.java index 9ff36bb..0ac9994 100644 --- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SupervisingRouteControllerAutoConfiguration.java +++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SupervisingRouteControllerAutoConfiguration.java @@ -16,11 +16,14 @@ */ package org.apache.camel.spring.boot; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Optional; import org.apache.camel.converter.TimePatternConverter; import org.apache.camel.impl.SupervisingRouteController; +import org.apache.camel.impl.SupervisingRouteControllerFilters; import org.apache.camel.spi.RouteController; import org.apache.camel.spring.boot.SupervisingRouteControllerConfiguration.BackOffConfiguration; import org.apache.camel.spring.boot.SupervisingRouteControllerConfiguration.RouteConfiguration; @@ -42,6 +45,8 @@ import org.springframework.context.annotation.Scope; public class SupervisingRouteControllerAutoConfiguration { @Autowired private SupervisingRouteControllerConfiguration configuration; + @Autowired(required = false) + private List<SupervisingRouteController.Filter> filters = Collections.emptyList(); @Bean @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) @@ -52,17 +57,23 @@ public class SupervisingRouteControllerAutoConfiguration { // Initial delay Optional.ofNullable(configuration.getInitialDelay()).map(TimePatternConverter::toMilliSeconds).ifPresent(controller::setInitialDelay); + // Filter list + controller.setFilters(filters); + // Back off controller.setDefaultBackOff(configureBackOff(Optional.empty(), configuration.getDefaultBackOff())); for (Map.Entry<String, RouteConfiguration> entry: configuration.getRoutes().entrySet()) { - controller.setBackOff( - entry.getKey(), - configureBackOff( - Optional.ofNullable(controller.getDefaultBackOff()), - entry.getValue().getBackOff() - ) - ); + final RouteConfiguration cfg = entry.getValue(); + final Optional<BackOff> defaultBackOff = Optional.ofNullable(controller.getDefaultBackOff()); + + if (!cfg.isSupervised()) { + // Mark this route as excluded from supervisor + controller.addFilter(new SupervisingRouteControllerFilters.BlackList(entry.getKey())); + } else { + // configure teh route + controller.setBackOff(entry.getKey(), configureBackOff(defaultBackOff, cfg.getBackOff())); + } } return controller; http://git-wip-us.apache.org/repos/asf/camel/blob/2b832e93/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SupervisingRouteControllerConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SupervisingRouteControllerConfiguration.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SupervisingRouteControllerConfiguration.java index 4ab2290..1c4096d 100644 --- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SupervisingRouteControllerConfiguration.java +++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SupervisingRouteControllerConfiguration.java @@ -75,10 +75,23 @@ public class SupervisingRouteControllerConfiguration { public static class RouteConfiguration { /** + * Control if the route should be supervised or not, default is true. + */ + private boolean supervise = true; + + /** * The back-off configuration from this route, inherits from default back-off */ private BackOffConfiguration backOff; + public boolean isSupervised() { + return supervise; + } + + public void setSupervise(boolean supervise) { + this.supervise = supervise; + } + public BackOffConfiguration getBackOff() { return backOff; } http://git-wip-us.apache.org/repos/asf/camel/blob/2b832e93/examples/camel-example-spring-boot-routecontroller/src/main/java/sample/camel/ApplicationRoutes.java ---------------------------------------------------------------------- diff --git a/examples/camel-example-spring-boot-routecontroller/src/main/java/sample/camel/ApplicationRoutes.java b/examples/camel-example-spring-boot-routecontroller/src/main/java/sample/camel/ApplicationRoutes.java index 7115570..fb6e2f5 100644 --- a/examples/camel-example-spring-boot-routecontroller/src/main/java/sample/camel/ApplicationRoutes.java +++ b/examples/camel-example-spring-boot-routecontroller/src/main/java/sample/camel/ApplicationRoutes.java @@ -41,8 +41,12 @@ public class ApplicationRoutes extends RouteBuilder { .log("From undertow ..."); from("undertow:http://localhost:9012") - .id("undertow-2") + .id("undertow2") .autoStartup(false) - .log("From undertow ..."); + .log("From undertow 2..."); + + from("undertow:http://localhost:9013") + .id("undertow3") + .log("From undertow 3..."); } } http://git-wip-us.apache.org/repos/asf/camel/blob/2b832e93/examples/camel-example-spring-boot-routecontroller/src/main/resources/application.properties ---------------------------------------------------------------------- diff --git a/examples/camel-example-spring-boot-routecontroller/src/main/resources/application.properties b/examples/camel-example-spring-boot-routecontroller/src/main/resources/application.properties index 10efe1c..8533f6b 100644 --- a/examples/camel-example-spring-boot-routecontroller/src/main/resources/application.properties +++ b/examples/camel-example-spring-boot-routecontroller/src/main/resources/application.properties @@ -19,7 +19,8 @@ debug = false logging.level.org.springframework = INFO logging.level.org.apache.camel.spring.boot = INFO -logging.level.org.apache.camel.impl = DEBUG +logging.level.org.apache.camel.impl = INFO +logging.level.org.apache.camel.impl.SupervisingRouteController = DEBUG logging.level.org.apache.camel.util.backoff = DEBUG logging.level.sample.camel = DEBUG @@ -42,3 +43,4 @@ camel.supervising.controller.default-back-off.delay = 5s camel.supervising.controller.default-back-off.max-attempts = 10 camel.supervising.controller.routes.undertow.back-off.delay = 10s camel.supervising.controller.routes.undertow.back-off.max-attempts = 3 +camel.supervising.controller.routes.undertow3.supervise = false