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
The following commit(s) were added to refs/heads/master by this push: new 49bbe86 CAMEL-15134: camel-health - Make routes health check discoverable via classpath. And remove JMX evaluators and make it simpler API to use. 49bbe86 is described below commit 49bbe860fa701f24e5d7168dd6558925a325ab07 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Fri May 29 12:29:39 2020 +0200 CAMEL-15134: camel-health - Make routes health check discoverable via classpath. And remove JMX evaluators and make it simpler API to use. --- ...CamelMicroProfileHealthCheckRepositoryTest.java | 10 +- .../apache/camel/health/HealthCheckRegistry.java | 43 ++-- .../apache/camel/health/HealthCheckRepository.java | 4 +- .../core/xml/AbstractCamelContextFactoryBean.java | 10 - .../apache/camel/routes-health-check-repository | 2 + .../camel/impl/health/AbstractHealthCheck.java | 3 + .../impl/health/DefaultHealthCheckRegistry.java | 56 ++-- .../impl/health/PerformanceCounterEvaluator.java | 31 --- .../camel/impl/health/RegistryRepository.java | 9 +- .../apache/camel/impl/health/RouteHealthCheck.java | 37 --- .../health/RoutePerformanceCounterEvaluators.java | 285 --------------------- .../impl/health/RoutesHealthCheckRepository.java | 71 +---- .../java/org/apache/camel/impl/health/package.html | 2 +- .../health/DefaultHealthCheckRegistryTest.java | 89 +++++-- .../apache/camel/impl/health/HealthCheckTest.java | 1 + .../camel/main/DefaultConfigurationConfigurer.java | 7 - 16 files changed, 155 insertions(+), 505 deletions(-) diff --git a/components/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthCheckRepositoryTest.java b/components/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthCheckRepositoryTest.java index 31ae2b9..b4b89d1 100644 --- a/components/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthCheckRepositoryTest.java +++ b/components/camel-microprofile-health/src/test/java/org/apache/camel/microprofile/health/CamelMicroProfileHealthCheckRepositoryTest.java @@ -23,7 +23,7 @@ import io.smallrye.health.SmallRyeHealth; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.health.HealthCheckRegistry; -import org.apache.camel.impl.health.RoutesHealthCheckRepository; +import org.apache.camel.health.HealthCheckRepository; import org.eclipse.microprofile.health.HealthCheckResponse.State; import org.junit.Test; @@ -32,7 +32,9 @@ public class CamelMicroProfileHealthCheckRepositoryTest extends CamelMicroProfil @Test public void testCamelHealthRepositoryUpStatus() { HealthCheckRegistry healthCheckRegistry = HealthCheckRegistry.get(context); - healthCheckRegistry.addRepository(new RoutesHealthCheckRepository()); + // enable routes health check + HealthCheckRepository hc = healthCheckRegistry.resolveHealthCheckRepositoryById("routes"); + healthCheckRegistry.register(hc); CamelMicroProfileReadinessCheck readinessCheck = new CamelMicroProfileReadinessCheck(); readinessCheck.setCamelContext(context); @@ -54,7 +56,9 @@ public class CamelMicroProfileHealthCheckRepositoryTest extends CamelMicroProfil @Test public void testCamelHealthRepositoryDownStatus() throws Exception { HealthCheckRegistry healthCheckRegistry = HealthCheckRegistry.get(context); - healthCheckRegistry.addRepository(new RoutesHealthCheckRepository()); + // enable routes health check + HealthCheckRepository hc = healthCheckRegistry.resolveHealthCheckRepositoryById("routes"); + healthCheckRegistry.register(hc); CamelMicroProfileReadinessCheck readinessCheck = new CamelMicroProfileReadinessCheck(); readinessCheck.setCamelContext(context); diff --git a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java index e7998e7..4b55514 100644 --- a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java +++ b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRegistry.java @@ -19,6 +19,7 @@ package org.apache.camel.health; import java.util.Collection; import java.util.Optional; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.camel.CamelContext; import org.apache.camel.CamelContextAware; @@ -27,11 +28,8 @@ import org.apache.camel.util.ObjectHelper; /** * A registry for health checks. - * <p> - * Note that this registry can be superseded by the future camel context internal - * registry, @see <a href="https://issues.apache.org/jira/browse/CAMEL-10792"/>. */ -public interface HealthCheckRegistry extends HealthCheckRepository, CamelContextAware, StaticService { +public interface HealthCheckRegistry extends CamelContextAware, StaticService { /** * Service factory key. @@ -49,34 +47,29 @@ public interface HealthCheckRegistry extends HealthCheckRepository, CamelContext HealthCheck resolveHealthCheckById(String id); /** - * Registers a service {@link HealthCheck}. - */ - boolean register(HealthCheck check); - - /** - * Unregisters a service {@link HealthCheck}. - */ - boolean unregister(HealthCheck check); - - /** - * Set the health check repositories to use.. + * Resolves {@link HealthCheckRepository} by id. + * + * Will first lookup in this {@link HealthCheckRegistry} and then {@link org.apache.camel.spi.Registry}, + * and lastly do classpath scanning via {@link org.apache.camel.spi.annotations.ServiceFactory}. + * The classpath scanning is attempted first with id-health-check-repository as the key, and then with id as fallback + * if not found the first time. */ - void setRepositories(Collection<HealthCheckRepository> repositories); + HealthCheckRepository resolveHealthCheckRepositoryById(String id); /** - * Get a collection of health check repositories. + * Registers a {@link HealthCheck}. */ - Collection<HealthCheckRepository> getRepositories(); + boolean register(HealthCheck check); /** - * Add an Health Check repository. + * Unregisters a {@link HealthCheck}. */ - boolean addRepository(HealthCheckRepository repository); + boolean unregister(HealthCheck check); /** - * Remove an Health Check repository. + * Registers a {@link HealthCheckRepository}. */ - boolean removeRepository(HealthCheckRepository repository); + boolean register(HealthCheckRepository repository); /** * A collection of health check IDs. @@ -112,4 +105,10 @@ public interface HealthCheckRegistry extends HealthCheckRepository, CamelContext static HealthCheckRegistry get(CamelContext context) { return context.getExtension(HealthCheckRegistry.class); } + + /** + * Returns a sequential {@code Stream} with the known {@link HealthCheck} + * as its source. + */ + Stream<HealthCheck> stream(); } diff --git a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRepository.java b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRepository.java index 39fdf75..8a8f727 100644 --- a/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRepository.java +++ b/core/camel-api/src/main/java/org/apache/camel/health/HealthCheckRepository.java @@ -18,10 +18,12 @@ package org.apache.camel.health; import java.util.stream.Stream; +import org.apache.camel.spi.HasId; + /** * A repository for health checks. */ -public interface HealthCheckRepository { +public interface HealthCheckRepository extends HasId { /** * Returns a sequential {@code Stream} with the known {@link HealthCheck} diff --git a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java index 125b399..0f854d1 100644 --- a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java +++ b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java @@ -49,7 +49,6 @@ import org.apache.camel.component.properties.PropertiesComponent; import org.apache.camel.component.properties.PropertiesLocation; import org.apache.camel.component.properties.PropertiesParser; import org.apache.camel.health.HealthCheckRegistry; -import org.apache.camel.health.HealthCheckRepository; import org.apache.camel.impl.engine.DefaultManagementStrategy; import org.apache.camel.impl.transformer.TransformerKey; import org.apache.camel.impl.validator.ValidatorKey; @@ -369,15 +368,6 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex } else { healthCheckRegistry = HealthCheckRegistry.get(getContext()); } - if (healthCheckRegistry != null) { - // Health check repository - Set<HealthCheckRepository> repositories = getContext().getRegistry().findByType(HealthCheckRepository.class); - if (org.apache.camel.util.ObjectHelper.isNotEmpty(repositories)) { - for (HealthCheckRepository repository : repositories) { - healthCheckRegistry.addRepository(repository); - } - } - } // UuidGenerator UuidGenerator uuidGenerator = getBeanForType(UuidGenerator.class); if (uuidGenerator != null) { diff --git a/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/routes-health-check-repository b/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/routes-health-check-repository new file mode 100644 index 0000000..f3e7322 --- /dev/null +++ b/core/camel-health/src/generated/resources/META-INF/services/org/apache/camel/routes-health-check-repository @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.impl.health.RoutesHealthCheckRepository diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/AbstractHealthCheck.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/AbstractHealthCheck.java index 351b339..e4a9f53 100644 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/AbstractHealthCheck.java +++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/AbstractHealthCheck.java @@ -31,6 +31,9 @@ import org.apache.camel.util.ObjectHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Base implementation for {@link HealthCheck}. + */ public abstract class AbstractHealthCheck implements HealthCheck { public static final String CHECK_ID = "check.id"; public static final String CHECK_GROUP = "check.group"; diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java index 81750e4..db0df07 100644 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java +++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/DefaultHealthCheckRegistry.java @@ -16,8 +16,6 @@ */ package org.apache.camel.impl.health; -import java.util.Collection; -import java.util.Collections; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.stream.Stream; @@ -110,7 +108,31 @@ public class DefaultHealthCheckRegistry extends ServiceSupport implements Health } @Override + public HealthCheckRepository resolveHealthCheckRepositoryById(String id) { + HealthCheckRepository answer = + repositories.stream().filter(h -> h.getId().equals(id)).findFirst() + .orElse(camelContext.getRegistry().findByTypeWithName(HealthCheckRepository.class).get(id)); + if (answer == null) { + // discover via classpath (try first via -health-check-repository and then id as-is) + FactoryFinder ff = camelContext.adapt(ExtendedCamelContext.class).getDefaultFactoryFinder(); + Class<? extends HealthCheckRepository> clazz = (Class<? extends HealthCheckRepository>) ff.findOptionalClass(id + "-health-check-repository").orElse(null); + if (clazz == null) { + clazz = (Class<? extends HealthCheckRepository>) ff.findOptionalClass(id).orElse(null); + } + if (clazz != null) { + answer = camelContext.getInjector().newInstance(clazz); + } + } + + return answer; + } + + @Override public boolean register(HealthCheck check) { + if (check == null) { + throw new IllegalArgumentException(); + } + boolean result = checks.add(check); if (result) { if (check instanceof CamelContextAware) { @@ -134,35 +156,19 @@ public class DefaultHealthCheckRegistry extends ServiceSupport implements Health } @Override - public void setRepositories(Collection<HealthCheckRepository> repositories) { - this.repositories.clear(); - this.repositories.addAll(repositories); - } + public boolean register(HealthCheckRepository repository) { + if (repository == null) { + throw new IllegalArgumentException(); + } - @Override - public Collection<HealthCheckRepository> getRepositories() { - return Collections.unmodifiableCollection(repositories); - } + boolean result = this.repositories.add(repository); - @Override - public boolean addRepository(HealthCheckRepository repository) { - boolean result = repositories.add(repository); if (result) { if (repository instanceof CamelContextAware) { - ((CamelContextAware) repository).setCamelContext(getCamelContext()); - - LOG.debug("HealthCheckRepository {} successfully registered", repository); + ((CamelContextAware) repository).setCamelContext(camelContext); } - } - return result; - } - - @Override - public boolean removeRepository(HealthCheckRepository repository) { - boolean result = repositories.remove(repository); - if (result) { - LOG.debug("HealthCheckRepository with {} successfully un-registered", repository); + LOG.debug("HealthCheckRepository with id {} successfully registered", repository.getId()); } return result; diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/PerformanceCounterEvaluator.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/PerformanceCounterEvaluator.java deleted file mode 100644 index 92c290f..0000000 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/PerformanceCounterEvaluator.java +++ /dev/null @@ -1,31 +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.impl.health; - -import java.util.Map; - -import org.apache.camel.api.management.mbean.ManagedPerformanceCounterMBean; -import org.apache.camel.health.HealthCheckResultBuilder; - -@FunctionalInterface -public interface PerformanceCounterEvaluator<T extends ManagedPerformanceCounterMBean> { - - /** - * Check the given performance counter. - */ - void test(T counter, HealthCheckResultBuilder builder, Map<String, Object> options); -} diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/RegistryRepository.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/RegistryRepository.java index c9c0e1b..edb735e 100644 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/RegistryRepository.java +++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/RegistryRepository.java @@ -25,9 +25,16 @@ import org.apache.camel.health.HealthCheckRepository; /** * {@link HealthCheckRepository} that uses the Camel {@link org.apache.camel.spi.Registry}. + * + * Camel will use this by default, so there is no need to register this manually. */ public class RegistryRepository implements CamelContextAware, HealthCheckRepository { - private volatile CamelContext context; + private CamelContext context; + + @Override + public String getId() { + return "registry-health-check-repository"; + } @Override public void setCamelContext(CamelContext camelContext) { diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/RouteHealthCheck.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/RouteHealthCheck.java index 1660b1e..0693537 100644 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/RouteHealthCheck.java +++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/RouteHealthCheck.java @@ -16,19 +16,12 @@ */ package org.apache.camel.impl.health; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; import java.util.Map; import org.apache.camel.CamelContext; import org.apache.camel.Route; import org.apache.camel.ServiceStatus; -import org.apache.camel.api.management.ManagedCamelContext; -import org.apache.camel.api.management.mbean.ManagedRouteMBean; import org.apache.camel.health.HealthCheckResultBuilder; -import org.apache.camel.util.ObjectHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,22 +32,10 @@ public class RouteHealthCheck extends AbstractHealthCheck { private static final Logger LOGGER = LoggerFactory.getLogger(RouteHealthCheck.class); private final Route route; - private final List<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators; public RouteHealthCheck(Route route) { - this(route, null); - } - - public RouteHealthCheck(Route route, Collection<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators) { super("camel", "route:" + route.getId()); - this.route = route; - - if (ObjectHelper.isNotEmpty(evaluators)) { - this.evaluators = new ArrayList<>(evaluators); - } else { - this.evaluators = Collections.emptyList(); - } } @Override @@ -86,24 +67,6 @@ public class RouteHealthCheck extends AbstractHealthCheck { // route is always up as it is externally managed. builder.up(); } - - if (builder.state() != State.DOWN) { - // If JMX is enabled, use the Managed MBeans to determine route - // health based on performance counters. - ManagedCamelContext managedCamelContext = context.getExtension(ManagedCamelContext.class); - if (managedCamelContext != null) { - ManagedRouteMBean managedRoute = managedCamelContext.getManagedRoute(route.getId()); - if (managedRoute != null && !evaluators.isEmpty()) { - for (PerformanceCounterEvaluator<ManagedRouteMBean> evaluator : evaluators) { - evaluator.test(managedRoute, builder, options); - - if (builder.state() == State.DOWN) { - break; - } - } - } - } - } } } } diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/RoutePerformanceCounterEvaluators.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/RoutePerformanceCounterEvaluators.java deleted file mode 100644 index 5f7f903..0000000 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/RoutePerformanceCounterEvaluators.java +++ /dev/null @@ -1,285 +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.impl.health; - -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.camel.api.management.mbean.ManagedRouteMBean; -import org.apache.camel.health.HealthCheckResultBuilder; - -public final class RoutePerformanceCounterEvaluators { - - private RoutePerformanceCounterEvaluators() { - } - - // ******************************** - // Helpers - // ******************************** - - public static PerformanceCounterEvaluator<ManagedRouteMBean> exchangesFailed(long threshold) { - return new ExchangesFailed(threshold); - } - - public static PerformanceCounterEvaluator<ManagedRouteMBean> exchangesInflight(long threshold) { - return new ExchangesInflight(threshold); - } - - public static PerformanceCounterEvaluator<ManagedRouteMBean> redeliveries(long threshold) { - return new Redeliveries(threshold); - } - - public static PerformanceCounterEvaluator<ManagedRouteMBean> externalRedeliveries(long threshold) { - return new ExternalRedeliveries(threshold); - } - - public static PerformanceCounterEvaluator<ManagedRouteMBean> lastProcessingTime(long timeThreshold, int failuresThreshold) { - return new LastProcessingTime(timeThreshold, failuresThreshold); - } - - public static PerformanceCounterEvaluator<ManagedRouteMBean> minProcessingTime(long timeThreshold, int failuresThreshold) { - return new MinProcessingTime(timeThreshold, failuresThreshold); - } - - public static PerformanceCounterEvaluator<ManagedRouteMBean> meanProcessingTime(long timeThreshold, int failuresThreshold) { - return new MeanProcessingTime(timeThreshold, failuresThreshold); - } - - public static PerformanceCounterEvaluator<ManagedRouteMBean> maxProcessingTime(long timeThreshold, int failuresThreshold) { - return new MaxProcessingTime(timeThreshold, failuresThreshold); - } - - // ******************************** - // Impls - // ******************************** - - public static final class ExchangesFailed implements PerformanceCounterEvaluator<ManagedRouteMBean> { - private final long threshold; - - public ExchangesFailed(long threshold) { - this.threshold = threshold; - } - - @Override - public void test(ManagedRouteMBean counter, HealthCheckResultBuilder builder, Map<String, Object> options) { - try { - long value = counter.getExchangesFailed(); - if (value > threshold) { - builder.down(); - } - - builder.detail("exchanges.failed", value); - builder.detail("exchanges.failed.threshold", threshold); - } catch (Exception e) { - } - } - } - - public static final class ExchangesInflight implements PerformanceCounterEvaluator<ManagedRouteMBean> { - private final long threshold; - - public ExchangesInflight(long threshold) { - this.threshold = threshold; - } - - @Override - public void test(ManagedRouteMBean counter, HealthCheckResultBuilder builder, Map<String, Object> options) { - try { - long value = counter.getExchangesInflight(); - if (value > threshold) { - builder.down(); - } - - builder.detail("exchanges.inflight", value); - builder.detail("exchanges.inflight.threshold", threshold); - } catch (Exception e) { - } - } - } - - public static final class Redeliveries implements PerformanceCounterEvaluator<ManagedRouteMBean> { - private final long threshold; - - public Redeliveries(long threshold) { - this.threshold = threshold; - } - - @Override - public void test(ManagedRouteMBean counter, HealthCheckResultBuilder builder, Map<String, Object> options) { - try { - long value = counter.getRedeliveries(); - if (value > threshold) { - builder.down(); - } - - builder.detail("exchanges.redeliveries", value); - builder.detail("exchanges.redeliveries.threshold", threshold); - } catch (Exception e) { - } - } - } - - public static final class ExternalRedeliveries implements PerformanceCounterEvaluator<ManagedRouteMBean> { - private final long threshold; - - public ExternalRedeliveries(long threshold) { - this.threshold = threshold; - } - - @Override - public void test(ManagedRouteMBean counter, HealthCheckResultBuilder builder, Map<String, Object> options) { - try { - long value = counter.getExternalRedeliveries(); - if (value > threshold) { - builder.down(); - } - - builder.detail("exchanges.external-redeliveries", value); - builder.detail("exchanges.external-redeliveries.threshold", threshold); - } catch (Exception e) { - } - } - } - - public static final class LastProcessingTime implements PerformanceCounterEvaluator<ManagedRouteMBean> { - private final long timeThreshold; - private final int failuresThreshold; - private final AtomicInteger failureCount = new AtomicInteger(); - - public LastProcessingTime(long timeThreshold, int failuresThreshold) { - this.timeThreshold = timeThreshold; - this.failuresThreshold = failuresThreshold; - } - - @Override - public void test(ManagedRouteMBean counter, HealthCheckResultBuilder builder, Map<String, Object> options) { - try { - long value = counter.getLastProcessingTime(); - if (value > timeThreshold) { - int newFailureCount = failureCount.incrementAndGet(); - - if (newFailureCount > failuresThreshold) { - builder.down(); - } - } else { - failureCount.set(0); - } - - builder.detail("exchanges.last-processing-time", value); - builder.detail("exchanges.last-processing-time.threshold.time", timeThreshold); - builder.detail("exchanges.last-processing-time.threshold.failures", failuresThreshold); - } catch (Exception e) { - } - } - } - - public static final class MinProcessingTime implements PerformanceCounterEvaluator<ManagedRouteMBean> { - private final long timeThreshold; - private final int failuresThreshold; - private final AtomicInteger failureCount = new AtomicInteger(); - - public MinProcessingTime(long timeThreshold, int failuresThreshold) { - this.timeThreshold = timeThreshold; - this.failuresThreshold = failuresThreshold; - } - - @Override - public void test(ManagedRouteMBean counter, HealthCheckResultBuilder builder, Map<String, Object> options) { - try { - long value = counter.getMinProcessingTime(); - if (value > timeThreshold) { - int newFailureCount = failureCount.incrementAndGet(); - - if (newFailureCount > failuresThreshold) { - builder.down(); - } - } else { - failureCount.set(0); - } - - builder.detail("exchanges.min-processing-time", value); - builder.detail("exchanges.min-processing-time.threshold.time", timeThreshold); - builder.detail("exchanges.min-processing-time.threshold.failures", failuresThreshold); - } catch (Exception e) { - } - } - } - - public static final class MeanProcessingTime implements PerformanceCounterEvaluator<ManagedRouteMBean> { - private final long timeThreshold; - private final int failuresThreshold; - private final AtomicInteger failureCount = new AtomicInteger(); - - public MeanProcessingTime(long timeThreshold, int failuresThreshold) { - this.timeThreshold = timeThreshold; - this.failuresThreshold = failuresThreshold; - } - - @Override - public void test(ManagedRouteMBean counter, HealthCheckResultBuilder builder, Map<String, Object> options) { - try { - long value = counter.getMeanProcessingTime(); - if (value > timeThreshold) { - int newFailureCount = failureCount.incrementAndGet(); - - if (newFailureCount > failuresThreshold) { - builder.down(); - } - } else { - failureCount.set(0); - } - - builder.detail("exchanges.mean-processing-time", value); - builder.detail("exchanges.mean-processing-time.threshold.time", timeThreshold); - builder.detail("exchanges.mean-processing-time.threshold.failures", failuresThreshold); - } catch (Exception e) { - } - } - } - - public static final class MaxProcessingTime implements PerformanceCounterEvaluator<ManagedRouteMBean> { - private final long timeThreshold; - private final int failuresThreshold; - private final AtomicInteger failureCount = new AtomicInteger(); - - public MaxProcessingTime(long timeThreshold, int failuresThreshold) { - this.timeThreshold = timeThreshold; - this.failuresThreshold = failuresThreshold; - } - - @Override - public void test(ManagedRouteMBean counter, HealthCheckResultBuilder builder, Map<String, Object> options) { - try { - long value = counter.getMaxProcessingTime(); - if (value > timeThreshold) { - int newFailureCount = failureCount.incrementAndGet(); - - if (newFailureCount > failuresThreshold) { - builder.down(); - } - } else { - failureCount.set(0); - } - - builder.detail("exchanges.max-processing-time", value); - builder.detail("exchanges.max-processing-time.threshold.time", timeThreshold); - builder.detail("exchanges.max-processing-time.threshold.failures", failuresThreshold); - } catch (Exception e) { - } - } - } -} diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/RoutesHealthCheckRepository.java b/core/camel-health/src/main/java/org/apache/camel/impl/health/RoutesHealthCheckRepository.java index 384eaf6..fe7288c 100644 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/RoutesHealthCheckRepository.java +++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/RoutesHealthCheckRepository.java @@ -17,33 +17,28 @@ package org.apache.camel.impl.health; import java.util.Collection; -import java.util.Collections; import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Stream; import org.apache.camel.CamelContext; import org.apache.camel.CamelContextAware; import org.apache.camel.DeferredContextBinding; import org.apache.camel.Route; -import org.apache.camel.api.management.mbean.ManagedRouteMBean; import org.apache.camel.health.HealthCheck; import org.apache.camel.health.HealthCheckRepository; +import org.apache.camel.spi.annotations.JdkService; /** * Repository for routes {@link HealthCheck}s. */ +@JdkService("routes-health-check-repository") @DeferredContextBinding public class RoutesHealthCheckRepository implements CamelContextAware, HealthCheckRepository { private final ConcurrentMap<Route, HealthCheck> checks; private Set<String> blacklist; - private List<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators; - private ConcurrentMap<String, Collection<PerformanceCounterEvaluator<ManagedRouteMBean>>> evaluatorMap; private volatile CamelContext context; public RoutesHealthCheckRepository() { @@ -56,6 +51,11 @@ public class RoutesHealthCheckRepository implements CamelContextAware, HealthChe } @Override + public String getId() { + return "routes"; + } + + @Override public CamelContext getCamelContext() { return context; } @@ -72,46 +72,6 @@ public class RoutesHealthCheckRepository implements CamelContextAware, HealthChe this.blacklist.add(routeId); } - public void setEvaluators(Collection<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators) { - evaluators.forEach(this::addEvaluator); - } - - public void addEvaluator(PerformanceCounterEvaluator<ManagedRouteMBean> evaluator) { - if (this.evaluators == null) { - this.evaluators = new CopyOnWriteArrayList<>(); - } - - this.evaluators.add(evaluator); - } - - public void setRoutesEvaluators(Map<String, Collection<PerformanceCounterEvaluator<ManagedRouteMBean>>> evaluators) { - evaluators.forEach(this::setRouteEvaluators); - } - - public void setRouteEvaluators(String routeId, Collection<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators) { - evaluators.forEach(evaluator -> addRouteEvaluator(routeId, evaluator)); - } - - public void addRouteEvaluator(String routeId, PerformanceCounterEvaluator<ManagedRouteMBean> evaluator) { - if (this.evaluatorMap == null) { - this.evaluatorMap = new ConcurrentHashMap<>(); - } - - this.evaluatorMap.computeIfAbsent(routeId, id -> new CopyOnWriteArrayList<>()).add(evaluator); - } - - public Stream<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators() { - return this.evaluators != null - ? this.evaluators.stream() - : Stream.empty(); - } - - public Stream<PerformanceCounterEvaluator<ManagedRouteMBean>> evaluators(String routeId) { - return this.evaluatorMap != null - ? evaluatorMap.getOrDefault(routeId, Collections.emptyList()).stream() - : Stream.empty(); - } - @Override public Stream<HealthCheck> stream() { // This is not really efficient as getRoutes() creates a copy of the routes @@ -143,20 +103,7 @@ public class RoutesHealthCheckRepository implements CamelContextAware, HealthChe } private HealthCheck toRouteHealthCheck(Route route) { - return checks.computeIfAbsent( - route, - r -> { - HealthCheck check = new RouteHealthCheck( - route, - evaluatorMap != null - ? evaluatorMap.getOrDefault(r.getId(), evaluators) - : evaluators - ); - - check.getConfiguration().setEnabled(true); - - return check; - } - ); + return checks.computeIfAbsent(route, r -> new RouteHealthCheck(route)); } + } diff --git a/core/camel-health/src/main/java/org/apache/camel/impl/health/package.html b/core/camel-health/src/main/java/org/apache/camel/impl/health/package.html index 8094cd2..19a90d7 100644 --- a/core/camel-health/src/main/java/org/apache/camel/impl/health/package.html +++ b/core/camel-health/src/main/java/org/apache/camel/impl/health/package.html @@ -21,7 +21,7 @@ </head> <body> -Camel Health Check implementations. +Camel Health Check implementation. </body> </html> diff --git a/core/camel-health/src/test/java/org/apache/camel/impl/health/DefaultHealthCheckRegistryTest.java b/core/camel-health/src/test/java/org/apache/camel/impl/health/DefaultHealthCheckRegistryTest.java index 0ef6c7e..384d0f2 100644 --- a/core/camel-health/src/test/java/org/apache/camel/impl/health/DefaultHealthCheckRegistryTest.java +++ b/core/camel-health/src/test/java/org/apache/camel/impl/health/DefaultHealthCheckRegistryTest.java @@ -19,12 +19,13 @@ package org.apache.camel.impl.health; import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.apache.camel.CamelContext; import org.apache.camel.CamelContextAware; +import org.apache.camel.builder.RouteBuilder; import org.apache.camel.health.HealthCheck; import org.apache.camel.health.HealthCheckRegistry; +import org.apache.camel.health.HealthCheckRepository; import org.apache.camel.health.HealthCheckResultBuilder; import org.apache.camel.impl.DefaultCamelContext; import org.junit.Assert; @@ -33,17 +34,12 @@ import org.junit.Test; public class DefaultHealthCheckRegistryTest { @Test - public void testDefaultHealthCheckRegistryRepositorySetter() { - HealthCheckRegistry registry1 = new DefaultHealthCheckRegistry(); - HealthCheckRegistry registry2 = new DefaultHealthCheckRegistry(); - registry1.addRepository(() -> Stream.of(new MyHealthCheck("G1", "1"))); - registry2.setRepositories(registry1.getRepositories()); - Assert.assertArrayEquals(registry1.getRepositories().toArray(), registry2.getRepositories().toArray()); - } - - @Test public void testDefaultHealthCheckRegistry() throws Exception { + CamelContext context = new DefaultCamelContext(); + DefaultHealthCheckRegistry registry = new DefaultHealthCheckRegistry(); + registry.setCamelContext(context); + registry.register(new MyHealthCheck("G1", "1")); registry.register(new MyHealthCheck("G1", "1")); registry.register(new MyHealthCheck("G1", "2")); @@ -62,20 +58,21 @@ public class DefaultHealthCheckRegistryTest { } @Test - public void testDefaultHealthCheckRegistryWithRepositories() throws Exception { - DefaultHealthCheckRegistry registry = new DefaultHealthCheckRegistry(); + public void testInjectCamelContext() throws Exception { + CamelContext context = new DefaultCamelContext(); + + HealthCheckRegistry registry = new DefaultHealthCheckRegistry(); + registry.setCamelContext(context); - registry.register(new MyHealthCheck("G1", "1")); registry.register(new MyHealthCheck("G1", "1")); registry.register(new MyHealthCheck("G1", "2")); registry.register(new MyHealthCheck("G2", "3")); - registry.addRepository(() -> Stream.of(new MyHealthCheck("G1", "1"), new MyHealthCheck("G1", "4"))); + context.start(); + registry.start(); List<HealthCheck> checks = registry.stream().collect(Collectors.toList()); - Assert.assertEquals(4, checks.size()); - Assert.assertEquals(1, checks.stream().filter(h -> h.getId().equals("4")).count()); - Assert.assertEquals(3, checks.stream().filter(h -> h.getGroup().equals("G1")).count()); + Assert.assertEquals(3, checks.size()); for (HealthCheck check : checks) { HealthCheck.Result response = check.call(); @@ -83,18 +80,19 @@ public class DefaultHealthCheckRegistryTest { Assert.assertEquals(HealthCheck.State.UP, response.getState()); Assert.assertFalse(response.getMessage().isPresent()); Assert.assertFalse(response.getError().isPresent()); + Assert.assertSame(context, ((CamelContextAware) check).getCamelContext()); } } @Test - public void testInjectCamelContext() throws Exception { + public void testDiscoverFromCamelRegistry() throws Exception { CamelContext context = new DefaultCamelContext(); HealthCheckRegistry registry = new DefaultHealthCheckRegistry(); registry.setCamelContext(context); - registry.register(new MyHealthCheck("G1", "1")); - registry.register(new MyHealthCheck("G1", "2")); + context.getRegistry().bind("check1", new MyHealthCheck("G1", "1")); + context.getRegistry().bind("check2", new MyHealthCheck("G1", "2")); registry.register(new MyHealthCheck("G2", "3")); context.start(); @@ -146,6 +144,57 @@ public class DefaultHealthCheckRegistryTest { } } + @Test + public void testResolveRoutesHealthCheck() throws Exception { + CamelContext context = new DefaultCamelContext(); + + HealthCheckRegistry registry = new DefaultHealthCheckRegistry(); + registry.setCamelContext(context); + HealthCheckRepository hc = registry.resolveHealthCheckRepositoryById("routes"); + Assert.assertNotNull(hc); + Assert.assertEquals("routes", hc.getId()); + Assert.assertTrue(hc instanceof RoutesHealthCheckRepository); + registry.register(hc); + + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").to("mock:foo").routeId("foo"); + from("direct:start2").to("mock:bar").routeId("bar"); + } + }); + + context.start(); + registry.start(); + + List<HealthCheck> checks = registry.stream().collect(Collectors.toList()); + Assert.assertEquals(2, checks.size()); + + for (HealthCheck check : checks) { + HealthCheck.Result response = check.call(); + + Assert.assertEquals(HealthCheck.State.UP, response.getState()); + Assert.assertFalse(response.getMessage().isPresent()); + Assert.assertFalse(response.getError().isPresent()); + } + + context.getRouteController().stopRoute("foo"); + + for (HealthCheck check : checks) { + HealthCheck.Result response = check.call(); + boolean foo = "foo".equals(response.getDetails().get("route.id")); + if (foo) { + Assert.assertEquals(HealthCheck.State.DOWN, response.getState()); + Assert.assertTrue(response.getMessage().isPresent()); + Assert.assertFalse(response.getError().isPresent()); + } else { + Assert.assertEquals(HealthCheck.State.UP, response.getState()); + Assert.assertFalse(response.getMessage().isPresent()); + Assert.assertFalse(response.getError().isPresent()); + } + } + } + private class MyHealthCheck extends AbstractHealthCheck implements CamelContextAware { private CamelContext context; diff --git a/core/camel-health/src/test/java/org/apache/camel/impl/health/HealthCheckTest.java b/core/camel-health/src/test/java/org/apache/camel/impl/health/HealthCheckTest.java index 973d2a1..3131014 100644 --- a/core/camel-health/src/test/java/org/apache/camel/impl/health/HealthCheckTest.java +++ b/core/camel-health/src/test/java/org/apache/camel/impl/health/HealthCheckTest.java @@ -25,6 +25,7 @@ import org.junit.Assert; import org.junit.Test; public class HealthCheckTest { + @Test public void testCheck() throws Exception { MyHealthCheck check = new MyHealthCheck(); 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 b52508c..9905cab 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 @@ -29,7 +29,6 @@ import org.apache.camel.TypeConverters; import org.apache.camel.cloud.ServiceRegistry; import org.apache.camel.cluster.CamelClusterService; import org.apache.camel.health.HealthCheckRegistry; -import org.apache.camel.health.HealthCheckRepository; import org.apache.camel.model.Model; import org.apache.camel.processor.interceptor.BacklogTracer; import org.apache.camel.spi.AsyncProcessorAwaitManager; @@ -375,12 +374,6 @@ public final class DefaultConfigurationConfigurer { healthCheckRegistry.setCamelContext(camelContext); } } - if (healthCheckRegistry != null) { - Set<HealthCheckRepository> hcrs = registry.findByType(HealthCheckRepository.class); - if (!hcrs.isEmpty()) { - hcrs.forEach(healthCheckRegistry::addRepository); - } - } // set the default thread pool profile if defined initThreadPoolProfiles(registry, camelContext);