Skip to content

CAMEL-19648: readiness/liveness probes #1010

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions core/camel-spring-boot/src/main/docs/spring-boot.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Original file line number Diff line number Diff line change
@@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add license header


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);
}
}
Original file line number Diff line number Diff line change
@@ -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<HealthCheck.Result> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add license header


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<HealthCheck.Result> results = HealthCheckHelper.invokeLiveness(camelContext);

boolean isLive = CamelProbesHelper.checkProbeState(results, LOG);

return isLive ?
LivenessState.CORRECT : LivenessState.BROKEN;
}
}
Original file line number Diff line number Diff line change
@@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add license header


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<HealthCheck.Result> results = HealthCheckHelper.invokeReadiness(camelContext);

boolean isReady = CamelProbesHelper.checkProbeState(results, LOG);

return isReady ?
ReadinessState.ACCEPTING_TRAFFIC : ReadinessState.REFUSING_TRAFFIC;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down