diff --git a/core/camel-spring-boot/src/main/docs/spring-boot.adoc b/core/camel-spring-boot/src/main/docs/spring-boot.adoc index 25c527237f25..e29685efea7a 100644 --- a/core/camel-spring-boot/src/main/docs/spring-boot.adoc +++ b/core/camel-spring-boot/src/main/docs/spring-boot.adoc @@ -416,3 +416,24 @@ implementing your custom https://docs.spring.io/spring-boot/docs/current/referen or by providing GraalVM JSON hint files that can be generated by the https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html#native-image.advanced.using-the-tracing-agent[Tracing Agent]. For more details about `GraalVM Native Image Support` in Spring Boot please refer to https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html + +== Camel Readiness and Liveness State Indicators + +Camel specific Readiness and Liveness checks can be added to a Spring Boot 3 application including respectively in the +readiness and livenss groups camelLivenessStateHealthIndicator and camelReadinessStateHealthIndicator. In particular: + +[source,properties] +---- +management.endpoint.health.group.liveness.include=livenessState,camelLivenessState +management.endpoint.health.group.readiness.include=readinessState,camelReadinessState +---- + +Using Camel specific readiness and liveness health indicators, the probes will be augmented with camel components +health checks that support this feature. In enable the probes locally, they need to be enabled + +[source,properties] +---- +management.endpoint.health.probes.enabled=true +---- + +Finally, http://localhost:8080/actuator/health/liveness will show the updated probe. \ No newline at end of file diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/CamelAvailabilityCheckAutoConfiguration.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/CamelAvailabilityCheckAutoConfiguration.java new file mode 100644 index 000000000000..758904783bc7 --- /dev/null +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/CamelAvailabilityCheckAutoConfiguration.java @@ -0,0 +1,48 @@ +/* + * 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.spring.boot.actuate.health; + +import org.apache.camel.CamelContext; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.actuate.health.liveness.CamelLivenessStateHealthIndicator; +import org.apache.camel.spring.boot.actuate.health.readiness.CamelReadinessStateHealthIndicator; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.availability.ApplicationAvailability; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@AutoConfigureAfter({CamelAutoConfiguration.class, ApplicationAvailabilityAutoConfiguration.class}) +@ConditionalOnBean(CamelAutoConfiguration.class) +public class CamelAvailabilityCheckAutoConfiguration { + + @Bean + public CamelLivenessStateHealthIndicator camelLivenessStateHealthIndicator( + ApplicationAvailability applicationAvailability, + CamelContext camelContext) { + return new CamelLivenessStateHealthIndicator(applicationAvailability, camelContext); + } + + @Bean + public CamelReadinessStateHealthIndicator camelReadinessStateHealthIndicator( + ApplicationAvailability applicationAvailability, + CamelContext camelContext) { + return new CamelReadinessStateHealthIndicator(applicationAvailability, camelContext); + } +} diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/CamelProbesHelper.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/CamelProbesHelper.java new file mode 100644 index 000000000000..81da7e4413bd --- /dev/null +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/CamelProbesHelper.java @@ -0,0 +1,46 @@ +/* + * 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.spring.boot.actuate.health; + +import org.apache.camel.health.HealthCheck; +import org.slf4j.Logger; + +import java.util.Collection; + +public final class CamelProbesHelper { + + private CamelProbesHelper() { + } + + public static boolean checkProbeState(Collection results, Logger log) { + boolean isUp = true; + for (HealthCheck.Result result : results) { + if (!HealthCheck.State.UP.equals(result.getState())) { + isUp = false; + + log.warn( + "Probe in group '{}', with id '{}' failed with message '{}'", + result.getCheck().getGroup(), + result.getCheck().getId(), + result.getMessage().orElse("")); + result.getError().ifPresent(error -> log.warn(error.getMessage(), error)); + } + } + + return isUp; + } +} diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/liveness/CamelLivenessStateHealthIndicator.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/liveness/CamelLivenessStateHealthIndicator.java new file mode 100644 index 000000000000..afb8e1622a51 --- /dev/null +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/liveness/CamelLivenessStateHealthIndicator.java @@ -0,0 +1,55 @@ +/* + * 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.spring.boot.actuate.health.liveness; + +import org.apache.camel.CamelContext; +import org.apache.camel.health.HealthCheck; +import org.apache.camel.health.HealthCheckHelper; +import org.apache.camel.spring.boot.actuate.health.CamelProbesHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.actuate.availability.LivenessStateHealthIndicator; +import org.springframework.boot.availability.ApplicationAvailability; +import org.springframework.boot.availability.AvailabilityState; +import org.springframework.boot.availability.LivenessState; + +import java.util.Collection; + +public class CamelLivenessStateHealthIndicator extends LivenessStateHealthIndicator { + + private static final Logger LOG = LoggerFactory.getLogger(CamelLivenessStateHealthIndicator.class); + + private final CamelContext camelContext; + + public CamelLivenessStateHealthIndicator( + ApplicationAvailability availability, + CamelContext camelContext) { + super(availability); + + this.camelContext = camelContext; + } + + @Override + protected AvailabilityState getState(ApplicationAvailability applicationAvailability) { + Collection results = HealthCheckHelper.invokeLiveness(camelContext); + + boolean isLive = CamelProbesHelper.checkProbeState(results, LOG); + + return isLive ? + LivenessState.CORRECT : LivenessState.BROKEN; + } +} diff --git a/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/readiness/CamelReadinessStateHealthIndicator.java b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/readiness/CamelReadinessStateHealthIndicator.java new file mode 100644 index 000000000000..dfb91b4eb6c7 --- /dev/null +++ b/core/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/actuate/health/readiness/CamelReadinessStateHealthIndicator.java @@ -0,0 +1,55 @@ +/* + * 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.spring.boot.actuate.health.readiness; + +import org.apache.camel.CamelContext; +import org.apache.camel.health.HealthCheck; +import org.apache.camel.health.HealthCheckHelper; +import org.apache.camel.spring.boot.actuate.health.CamelProbesHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.actuate.availability.ReadinessStateHealthIndicator; +import org.springframework.boot.availability.ApplicationAvailability; +import org.springframework.boot.availability.AvailabilityState; +import org.springframework.boot.availability.ReadinessState; + +import java.util.Collection; + +public class CamelReadinessStateHealthIndicator extends ReadinessStateHealthIndicator { + + private static final Logger LOG = LoggerFactory.getLogger(CamelReadinessStateHealthIndicator.class); + + private final CamelContext camelContext; + + public CamelReadinessStateHealthIndicator( + ApplicationAvailability availability, + CamelContext camelContext) { + super(availability); + + this.camelContext = camelContext; + } + + @Override + protected AvailabilityState getState(ApplicationAvailability applicationAvailability) { + Collection results = HealthCheckHelper.invokeReadiness(camelContext); + + boolean isReady = CamelProbesHelper.checkProbeState(results, LOG); + + return isReady ? + ReadinessState.ACCEPTING_TRAFFIC : ReadinessState.REFUSING_TRAFFIC; + } +} diff --git a/core/camel-spring-boot/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/core/camel-spring-boot/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 58e74acca754..8532b4fa82e5 100644 --- a/core/camel-spring-boot/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/core/camel-spring-boot/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -20,6 +20,7 @@ org.apache.camel.spring.boot.actuate.console.CamelDevConsoleAutoConfiguration org.apache.camel.spring.boot.actuate.endpoint.CamelRouteControllerEndpointAutoConfiguration org.apache.camel.spring.boot.actuate.endpoint.CamelRoutesEndpointAutoConfiguration org.apache.camel.spring.boot.actuate.health.CamelHealthCheckAutoConfiguration +org.apache.camel.spring.boot.actuate.health.CamelAvailabilityCheckAutoConfiguration org.apache.camel.spring.boot.actuate.info.CamelInfoAutoConfiguration org.apache.camel.spring.boot.cloud.CamelCloudAutoConfiguration org.apache.camel.spring.boot.cloud.CamelCloudServiceCallConfigurationAutoConfiguration