This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit aee36d9381b61926c40cf9d3433f9b1aab8a7313 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Fri May 8 14:32:17 2020 +0200 CAMEL-13535: Camel main - Allow to configure supervising route controller --- .../impl/engine/SupervisingRouteController.java | 19 ++- .../MainConfigurationPropertiesConfigurer.java | 35 +++++ .../camel-main-configuration-metadata.json | 7 + .../camel/main/DefaultConfigurationConfigurer.java | 37 +++++ .../camel/main/DefaultConfigurationProperties.java | 165 +++++++++++++++++++++ .../main/MainSupervisingRouteControllerTest.java | 110 ++++++++++++++ .../org/apache/camel/util/backoff/BackOff.java | 14 +- 7 files changed, 373 insertions(+), 14 deletions(-) diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/SupervisingRouteController.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/SupervisingRouteController.java index 890960a..ea990ec 100644 --- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/SupervisingRouteController.java +++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/SupervisingRouteController.java @@ -63,6 +63,9 @@ import org.slf4j.LoggerFactory; * settings for backoff between restarting routes. */ public class SupervisingRouteController extends DefaultRouteController { + + // TODO: Make SPI interface so we can separate this more nicely + private static final Logger LOGGER = LoggerFactory.getLogger(SupervisingRouteController.class); private final Object lock; private final AtomicBoolean contextStarted; @@ -92,7 +95,7 @@ public class SupervisingRouteController extends DefaultRouteController { this.listener = new CamelContextStartupListener(); this.listener.start(); } catch (Exception e) { - throw new RuntimeException(e); + throw RuntimeCamelException.wrapRuntimeException(e); } } @@ -169,6 +172,7 @@ public class SupervisingRouteController extends DefaultRouteController { /** * Add a filter used to determine the routes to supervise. */ + @Deprecated public void addFilter(Filter filter) { this.filters.add(filter); } @@ -176,11 +180,13 @@ public class SupervisingRouteController extends DefaultRouteController { /** * Sets the filters user to determine the routes to supervise. */ + @Deprecated public void setFilters(Collection<Filter> filters) { this.filters.clear(); this.filters.addAll(filters); } + @Deprecated public Collection<Filter> getFilters() { return Collections.unmodifiableList(filters); } @@ -432,7 +438,8 @@ public class SupervisingRouteController extends DefaultRouteController { BackOffTimer.Task task = timer.schedule(backOff, context -> { try { - logger.info("Try to restart route: {}", r.getId()); + long attempt = getBackOffContext(r.getId()).map(BackOffTimer.Task::getCurrentAttempts).orElse(0L); + logger.info("Restarting route: {} attempt: {}", r.getId(), attempt); doStartRoute(r, false, rx -> SupervisingRouteController.super.startRoute(rx.getId())); return false; @@ -453,7 +460,9 @@ public class SupervisingRouteController extends DefaultRouteController { final boolean stopped = status.isStopped() || status.isStopping(); if (backOffTask != null && backOffTask.getStatus() == BackOffTimer.Task.Status.Exhausted && stopped) { - LOGGER.info("Back-off for route {} is exhausted, no more attempts will be made and stop supervising it", route.getId()); + LOGGER.warn("Restarting route: {} is exhausted after {} attempts. No more attempts will be made" + + " and the route is no longer supervised by this route controller and remains as stopped.", + route.getId(), backOffTask.getCurrentAttempts() - 1); r.get().setRouteController(null); } } @@ -601,7 +610,7 @@ public class SupervisingRouteController extends DefaultRouteController { holder.get().setAutoStartup(false); if (contextStarted.get()) { - LOGGER.info("Context is already started: attempt to start route {}", route.getId()); + LOGGER.debug("Context is already started: attempt to start route {}", route.getId()); // Eventually delay the startup of the route a later time if (initialDelay.toMillis() > 0) { @@ -611,7 +620,7 @@ public class SupervisingRouteController extends DefaultRouteController { startRoute(holder); } } else { - LOGGER.info("Context is not yet started: defer route {} start", holder.getId()); + LOGGER.debug("Context is not yet started: defer route {} start", holder.getId()); } } } diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java index a06e794..f167ac7 100644 --- a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java +++ b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java @@ -105,6 +105,20 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "PackageScanRouteBuilders": target.setPackageScanRouteBuilders(property(camelContext, java.lang.String.class, value)); return true; case "producertemplatecachesize": case "ProducerTemplateCacheSize": target.setProducerTemplateCacheSize(property(camelContext, int.class, value)); return true; + case "routecontrollerbackoffdelay": + case "RouteControllerBackOffDelay": target.setRouteControllerBackOffDelay(property(camelContext, long.class, value)); return true; + case "routecontrollerbackoffmaxattempts": + case "RouteControllerBackOffMaxAttempts": target.setRouteControllerBackOffMaxAttempts(property(camelContext, long.class, value)); return true; + case "routecontrollerbackoffmaxdelay": + case "RouteControllerBackOffMaxDelay": target.setRouteControllerBackOffMaxDelay(property(camelContext, long.class, value)); return true; + case "routecontrollerbackoffmaxelapsedtime": + case "RouteControllerBackOffMaxElapsedTime": target.setRouteControllerBackOffMaxElapsedTime(property(camelContext, long.class, value)); return true; + case "routecontrollerbackoffmultiplier": + case "RouteControllerBackOffMultiplier": target.setRouteControllerBackOffMultiplier(property(camelContext, double.class, value)); return true; + case "routecontrollerenabled": + case "RouteControllerEnabled": target.setRouteControllerEnabled(property(camelContext, boolean.class, value)); return true; + case "routecontrollerinitialdelay": + case "RouteControllerInitialDelay": target.setRouteControllerInitialDelay(property(camelContext, long.class, value)); return true; case "routefilterexcludepattern": case "RouteFilterExcludePattern": target.setRouteFilterExcludePattern(property(camelContext, java.lang.String.class, value)); return true; case "routefilterincludepattern": @@ -211,6 +225,13 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp answer.put("Name", java.lang.String.class); answer.put("PackageScanRouteBuilders", java.lang.String.class); answer.put("ProducerTemplateCacheSize", int.class); + answer.put("RouteControllerBackOffDelay", long.class); + answer.put("RouteControllerBackOffMaxAttempts", long.class); + answer.put("RouteControllerBackOffMaxDelay", long.class); + answer.put("RouteControllerBackOffMaxElapsedTime", long.class); + answer.put("RouteControllerBackOffMultiplier", double.class); + answer.put("RouteControllerEnabled", boolean.class); + answer.put("RouteControllerInitialDelay", long.class); answer.put("RouteFilterExcludePattern", java.lang.String.class); answer.put("RouteFilterIncludePattern", java.lang.String.class); answer.put("RoutesBuilderClasses", java.lang.String.class); @@ -332,6 +353,20 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "PackageScanRouteBuilders": return target.getPackageScanRouteBuilders(); case "producertemplatecachesize": case "ProducerTemplateCacheSize": return target.getProducerTemplateCacheSize(); + case "routecontrollerbackoffdelay": + case "RouteControllerBackOffDelay": return target.getRouteControllerBackOffDelay(); + case "routecontrollerbackoffmaxattempts": + case "RouteControllerBackOffMaxAttempts": return target.getRouteControllerBackOffMaxAttempts(); + case "routecontrollerbackoffmaxdelay": + case "RouteControllerBackOffMaxDelay": return target.getRouteControllerBackOffMaxDelay(); + case "routecontrollerbackoffmaxelapsedtime": + case "RouteControllerBackOffMaxElapsedTime": return target.getRouteControllerBackOffMaxElapsedTime(); + case "routecontrollerbackoffmultiplier": + case "RouteControllerBackOffMultiplier": return target.getRouteControllerBackOffMultiplier(); + case "routecontrollerenabled": + case "RouteControllerEnabled": return target.isRouteControllerEnabled(); + case "routecontrollerinitialdelay": + case "RouteControllerInitialDelay": return target.getRouteControllerInitialDelay(); case "routefilterexcludepattern": case "RouteFilterExcludePattern": return target.getRouteFilterExcludePattern(); case "routefilterincludepattern": diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json index ab41e7c..5727428 100644 --- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json +++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json @@ -50,6 +50,13 @@ { "name": "camel.main.name", "description": "Sets the name of the CamelContext.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.main.packageScanRouteBuilders", "description": "Sets package names for scanning for org.apache.camel.builder.RouteBuilder classes as candidates to be included. If you are using Spring Boot then its instead recommended to use Spring Boots component scanning and annotate your route builder classes with Component. In other words only use this for Camel Main in standalone mode.", "sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": "string", "javaTy [...] { "name": "camel.main.producerTemplateCacheSize", "description": "Producer template endpoints cache size.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "int", "defaultValue": 1000 }, + { "name": "camel.main.routeControllerBackOffDelay", "description": "Backoff delay in millis when restarting a route that failed to startup.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "long" }, + { "name": "camel.main.routeControllerBackOffMaxAttempts", "description": "Backoff maximum number of attempts to restart a route that failed to startup. When this threshold has been exceeded then the controller will give up attempting to restart the route, and the route will remain as stopped.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "long" }, + { "name": "camel.main.routeControllerBackOffMaxDelay", "description": "Backoff maximum delay in millis when restarting a route that failed to startup.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "long" }, + { "name": "camel.main.routeControllerBackOffMaxElapsedTime", "description": "Backoff maximum elapsed time in millis, after which the backoff should be considered exhausted and no more attempts should be made.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "long" }, + { "name": "camel.main.routeControllerBackOffMultiplier", "description": "Backoff multiplier to use for exponential backoff. This is used to extend the delay between restart attempts.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "number", "javaType": "double" }, + { "name": "camel.main.routeControllerEnabled", "description": "To enable using supervising route controller which allows Camel to startup and then the controller takes care of starting the routes in a safe manner. This can be used when you want to startup Camel despite a route may otherwise fail fast during startup and cause Camel to fail to startup as well. By delegating the route startup to the supervising route controller then its manages the startup using a background thread. The [...] + { "name": "camel.main.routeControllerInitialDelay", "description": "Initial delay in milli seconds before the route controller starts, after CamelContext has been started.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "long" }, { "name": "camel.main.routeFilterExcludePattern", "description": "Used for filtering routes routes matching the given pattern, which follows the following rules: - Match by route id - Match by route input endpoint uri The matching is using exact match, by wildcard and regular expression as documented by PatternHelper#matchPattern(String,String) . For example to only include routes which starts with foo in their route id's, use: include=foo* And to exclude routes which starts from [...] { "name": "camel.main.routeFilterIncludePattern", "description": "Used for filtering routes routes matching the given pattern, which follows the following rules: - Match by route id - Match by route input endpoint uri The matching is using exact match, by wildcard and regular expression as documented by PatternHelper#matchPattern(String,String) . For example to only include routes which starts with foo in their route id's, use: include=foo* And to exclude routes which starts from [...] { "name": "camel.main.routesBuilderClasses", "description": "Sets classes names that implement RoutesBuilder .", "sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": "string", "javaType": "java.lang.String" }, diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java index d945450..29a7363 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationConfigurer.java @@ -31,6 +31,7 @@ import org.apache.camel.cluster.CamelClusterService; import org.apache.camel.health.HealthCheckRegistry; import org.apache.camel.health.HealthCheckRepository; import org.apache.camel.health.HealthCheckService; +import org.apache.camel.impl.engine.SupervisingRouteController; import org.apache.camel.model.Model; import org.apache.camel.processor.interceptor.BacklogTracer; import org.apache.camel.spi.AsyncProcessorAwaitManager; @@ -65,6 +66,7 @@ import org.apache.camel.spi.UnitOfWorkFactory; import org.apache.camel.spi.UuidGenerator; import org.apache.camel.support.jsse.GlobalSSLContextParametersSupplier; import org.apache.camel.util.ObjectHelper; +import org.apache.camel.util.backoff.BackOff; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -176,6 +178,41 @@ public final class DefaultConfigurationConfigurer { if (config.getRouteFilterIncludePattern() != null || config.getRouteFilterExcludePattern() != null) { camelContext.getExtension(Model.class).setRouteFilterPattern(config.getRouteFilterIncludePattern(), config.getRouteFilterExcludePattern()); } + + // supervisting route controller + if (config.isRouteControllerEnabled()) { + SupervisingRouteController src = new SupervisingRouteController(); + src.setCamelContext(camelContext); + if (config.getRouteControllerInitialDelay() > 0) { + src.setInitialDelay(config.getRouteControllerInitialDelay()); + } + BackOff.Builder builder = BackOff.builder(); + boolean flag = false; + if (config.getRouteControllerBackOffDelay() > 0) { + builder.delay(config.getRouteControllerBackOffDelay()); + flag = true; + } + if (config.getRouteControllerBackOffMaxDelay() > 0) { + builder.maxDelay(config.getRouteControllerBackOffMaxDelay()); + flag = true; + } + if (config.getRouteControllerBackOffMaxAttempts() > 0) { + builder.maxAttempts(config.getRouteControllerBackOffMaxAttempts()); + flag = true; + } + if (config.getRouteControllerBackOffMaxElapsedTime() > 0) { + builder.maxElapsedTime(config.getRouteControllerBackOffMaxElapsedTime()); + flag = true; + } + if (config.getRouteControllerBackOffMultiplier() > 0) { + builder.multiplier(config.getRouteControllerBackOffMultiplier()); + flag = true; + } + if (flag) { + src.setDefaultBackOff(builder.build()); + } + camelContext.setRouteController(src); + } } /** diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java index bd27e5c..0a56ebf 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java @@ -81,6 +81,13 @@ public abstract class DefaultConfigurationProperties<T> { private String xmlRoutes = "classpath:camel/*.xml"; private String xmlRests = "classpath:camel-rest/*.xml"; private boolean lightweight; + private boolean routeControllerEnabled; + private long routeControllerInitialDelay; + private long routeControllerBackOffDelay; + private long routeControllerBackOffMaxDelay; + private long routeControllerBackOffMaxElapsedTime; + private long routeControllerBackOffMaxAttempts; + private double routeControllerBackOffMultiplier; // getter and setters // -------------------------------------------------------------- @@ -890,6 +897,95 @@ public abstract class DefaultConfigurationProperties<T> { this.lightweight = lightweight; } + public boolean isRouteControllerEnabled() { + return routeControllerEnabled; + } + + /** + * To enable using supervising route controller which allows Camel to startup + * and then the controller takes care of starting the routes in a safe manner. + * + * This can be used when you want to startup Camel despite a route may otherwise + * fail fast during startup and cause Camel to fail to startup as well. By delegating + * the route startup to the supervising route controller then its manages the startup + * using a background thread. The controller allows to be configured with various + * settings to attempt to restart failing routes. + */ + public void setRouteControllerEnabled(boolean routeControllerEnabled) { + this.routeControllerEnabled = routeControllerEnabled; + } + + public long getRouteControllerInitialDelay() { + return routeControllerInitialDelay; + } + + /** + * Initial delay in milli seconds before the route controller starts, after + * CamelContext has been started. + */ + public void setRouteControllerInitialDelay(long routeControllerInitialDelay) { + this.routeControllerInitialDelay = routeControllerInitialDelay; + } + + public long getRouteControllerBackOffDelay() { + return routeControllerBackOffDelay; + } + + /** + * Backoff delay in millis when restarting a route that failed to startup. + */ + public void setRouteControllerBackOffDelay(long routeControllerBackOffDelay) { + this.routeControllerBackOffDelay = routeControllerBackOffDelay; + } + + public long getRouteControllerBackOffMaxDelay() { + return routeControllerBackOffMaxDelay; + } + + /** + * Backoff maximum delay in millis when restarting a route that failed to startup. + */ + public void setRouteControllerBackOffMaxDelay(long routeControllerBackOffMaxDelay) { + this.routeControllerBackOffMaxDelay = routeControllerBackOffMaxDelay; + } + + public long getRouteControllerBackOffMaxElapsedTime() { + return routeControllerBackOffMaxElapsedTime; + } + + /** + * Backoff maximum elapsed time in millis, after which the backoff should be considered + * exhausted and no more attempts should be made. + */ + public void setRouteControllerBackOffMaxElapsedTime(long routeControllerBackOffMaxElapsedTime) { + this.routeControllerBackOffMaxElapsedTime = routeControllerBackOffMaxElapsedTime; + } + + public long getRouteControllerBackOffMaxAttempts() { + return routeControllerBackOffMaxAttempts; + } + + /** + * Backoff maximum number of attempts to restart a route that failed to startup. + * When this threshold has been exceeded then the controller will give up + * attempting to restart the route, and the route will remain as stopped. + */ + public void setRouteControllerBackOffMaxAttempts(long routeControllerBackOffMaxAttempts) { + this.routeControllerBackOffMaxAttempts = routeControllerBackOffMaxAttempts; + } + + public double getRouteControllerBackOffMultiplier() { + return routeControllerBackOffMultiplier; + } + + /** + * Backoff multiplier to use for exponential backoff. This is used to extend the delay + * between restart attempts. + */ + public void setRouteControllerBackOffMultiplier(double routeControllerBackOffMultiplier) { + this.routeControllerBackOffMultiplier = routeControllerBackOffMultiplier; + } + // fluent builders // -------------------------------------------------------------- @@ -1537,4 +1633,73 @@ public abstract class DefaultConfigurationProperties<T> { this.lightweight = lightweight; return (T) this; } + + /** + * To enable using supervising route controller which allows Camel to startup + * and then the controller takes care of starting the routes in a safe manner. + * + * This can be used when you want to startup Camel despite a route may otherwise + * fail fast during startup and cause Camel to fail to startup as well. By delegating + * the route startup to the supervising route controller then its manages the startup + * using a background thread. The controller allows to be configured with various + * settings to attempt to restart failing routes. + */ + public T withRouteControllerEnabled(boolean routeControllerEnabled) { + this.routeControllerEnabled = routeControllerEnabled; + return (T) this; + } + + /** + * Initial delay in milli seconds before the route controller starts, after + * CamelContext has been started. + */ + public T withRouteControllerInitialDelay(long routeControllerInitialDelay) { + this.routeControllerInitialDelay = routeControllerInitialDelay; + return (T) this; + } + + /** + * Backoff delay in millis when restarting a route that failed to startup. + */ + public T withRouteControllerBackOffDelay(long routeControllerBackOffDelay) { + this.routeControllerBackOffDelay = routeControllerBackOffDelay; + return (T) this; + } + + /** + * Backoff maximum delay in millis when restarting a route that failed to startup. + */ + public T withRouteControllerBackOffMaxDelay(long routeControllerBackOffMaxDelay) { + this.routeControllerBackOffMaxDelay = routeControllerBackOffMaxDelay; + return (T) this; + } + + /** + * Backoff maximum elapsed time in millis, after which the backoff should be considered + * exhausted and no more attempts should be made. + */ + public T withRouteControllerBackOffMaxElapsedTime(long routeControllerBackOffMaxElapsedTime) { + this.routeControllerBackOffMaxElapsedTime = routeControllerBackOffMaxElapsedTime; + return (T) this; + } + + /** + * Backoff maximum number of attempts to restart a route that failed to startup. + * When this threshold has been exceeded then the controller will give up + * attempting to restart the route, and the route will remain as stopped. + */ + public T withRouteControllerBackOffMaxAttempts(long routeControllerBackOffMaxAttempts) { + this.routeControllerBackOffMaxAttempts = routeControllerBackOffMaxAttempts; + return (T) this; + } + + /** + * Backoff multiplier to use for exponential backoff. This is used to extend the delay + * between restart attempts. + */ + public T withRouteControllerBackOffMultiplier(double routeControllerBackOffMultiplier) { + this.routeControllerBackOffMultiplier = routeControllerBackOffMultiplier; + return (T) this; + } + } diff --git a/core/camel-main/src/test/java/org/apache/camel/main/MainSupervisingRouteControllerTest.java b/core/camel-main/src/test/java/org/apache/camel/main/MainSupervisingRouteControllerTest.java new file mode 100644 index 0000000..d91699d --- /dev/null +++ b/core/camel-main/src/test/java/org/apache/camel/main/MainSupervisingRouteControllerTest.java @@ -0,0 +1,110 @@ +/* + * 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.main; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.camel.Consumer; +import org.apache.camel.Endpoint; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.component.seda.SedaComponent; +import org.apache.camel.component.seda.SedaConsumer; +import org.apache.camel.component.seda.SedaEndpoint; +import org.junit.Assert; +import org.junit.Test; + +public class MainSupervisingRouteControllerTest extends Assert { + + @Test + public void testMain() throws Exception { + // lets make a simple route + Main main = new Main(); + main.configure().addRoutesBuilder(new MyRoute()); + main.configure().setRouteControllerEnabled(true); + main.configure().setRouteControllerBackOffDelay(250); + main.configure().setRouteControllerBackOffMaxAttempts(3); + main.configure().setRouteControllerInitialDelay(1000); + + main.start(); + + MockEndpoint mock = main.getCamelContext().getEndpoint("mock:foo", MockEndpoint.class); + mock.expectedMinimumMessageCount(3); + + MockEndpoint mock2 = main.getCamelContext().getEndpoint("mock:cheese", MockEndpoint.class); + mock2.expectedMessageCount(0); + + MockEndpoint.assertIsSatisfied(10, TimeUnit.SECONDS, mock, mock2); + + assertEquals("Started", main.camelContext.getRouteController().getRouteStatus("foo").toString()); + // cheese was not able to start + assertEquals("Stopped", main.camelContext.getRouteController().getRouteStatus("cheese").toString()); + + main.stop(); + } + + private class MyRoute extends RouteBuilder { + @Override + public void configure() throws Exception { + getContext().addComponent("jms", new MyJmsComponent()); + + from("timer:foo").to("mock:foo").routeId("foo"); + + from("jms:cheese").to("mock:cheese").routeId("cheese"); + } + } + + private class MyJmsComponent extends SedaComponent { + + @Override + protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception { + return new MyJmsEndpoint(); + } + } + + private class MyJmsEndpoint extends SedaEndpoint { + + public MyJmsEndpoint() { + super(); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + return new MyJmsConsumer(this, processor); + } + + @Override + protected String createEndpointUri() { + return "jms:cheese"; + } + } + + private class MyJmsConsumer extends SedaConsumer { + + public MyJmsConsumer(SedaEndpoint endpoint, Processor processor) { + super(endpoint, processor); + } + + @Override + protected void doStart() throws Exception { + throw new IllegalArgumentException("Cannot start"); + } + } + +} diff --git a/core/camel-util/src/main/java/org/apache/camel/util/backoff/BackOff.java b/core/camel-util/src/main/java/org/apache/camel/util/backoff/BackOff.java index d96fca8..7b6d240 100644 --- a/core/camel-util/src/main/java/org/apache/camel/util/backoff/BackOff.java +++ b/core/camel-util/src/main/java/org/apache/camel/util/backoff/BackOff.java @@ -17,6 +17,7 @@ package org.apache.camel.util.backoff; import java.time.Duration; +import java.time.temporal.TemporalUnit; import java.util.concurrent.TimeUnit; import org.apache.camel.util.ObjectHelper; @@ -52,9 +53,6 @@ public final class BackOff { // Properties // ************************************* - /** - * @return the delay to wait before retry the operation. - */ public Duration getDelay() { return delay; } @@ -96,8 +94,6 @@ public final class BackOff { /** * The maximum number of attempts after which the back-off should be considered * exhausted and no more attempts should be made. - * - * @param maxAttempts */ public void setMaxAttempts(Long maxAttempts) { this.maxAttempts = maxAttempts; @@ -116,13 +112,13 @@ public final class BackOff { @Override public String toString() { - return "BackOff{" + return "BackOff[" + "delay=" + delay - + ", maxDelay=" + maxDelay - + ", maxElapsedTime=" + maxElapsedTime + + ", maxDelay=" + (maxDelay != MAX_DURATION ? maxDelay : "") + + ", maxElapsedTime=" + (maxElapsedTime != MAX_DURATION ? maxElapsedTime : "") + ", maxAttempts=" + maxAttempts + ", multiplier=" + multiplier - + '}'; + + ']'; } // *****************************************