From 9c638b8d3f31f47494ebf9de0ee11e69f517fb0a Mon Sep 17 00:00:00 2001
From: cdfive <176402936@qq.com>
Date: Sun, 26 May 2019 15:46:09 +0800
Subject: [PATCH 1/4] Add SentinelHealthIndicator to do some health check for
Sentinel #265
---
.../src/main/resources/application.properties | 4 +-
.../SentinelEndpointAutoConfiguration.java | 7 ++
.../endpoint/SentinelHealthIndicator.java | 67 ++++++++++++++
.../SentinelHealthIndicatorTests.java | 90 +++++++++++++++++++
4 files changed, 167 insertions(+), 1 deletion(-)
create mode 100644 spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java
create mode 100644 spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicatorTests.java
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
index baa1dba3..71862fe2 100644
--- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
@@ -1,6 +1,8 @@
spring.application.name=sentinel-example
server.port=18083
management.endpoints.web.exposure.include=*
+management.endpoint.health.show-details=always
+
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true
@@ -19,4 +21,4 @@ spring.cloud.sentinel.datasource.ds4.file.file=classpath: system.json
spring.cloud.sentinel.datasource.ds4.file.rule-type=system
spring.cloud.sentinel.datasource.ds5.file.file=classpath: param-flow.json
-spring.cloud.sentinel.datasource.ds5.file.rule-type=param-flow
+spring.cloud.sentinel.datasource.ds5.file.rule-type=param_flow
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
index 7c9b5d1c..7388147a 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
@@ -17,6 +17,7 @@
package org.springframework.cloud.alibaba.sentinel.endpoint;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
+import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -38,4 +39,10 @@ public class SentinelEndpointAutoConfiguration {
return new SentinelEndpoint(sentinelProperties);
}
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnEnabledHealthIndicator("sentinel")
+ public SentinelHealthIndicator sentinelHealthIndicator(SentinelProperties sentinelProperties) {
+ return new SentinelHealthIndicator(sentinelProperties);
+ }
}
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java
new file mode 100644
index 00000000..82102100
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java
@@ -0,0 +1,67 @@
+package org.springframework.cloud.alibaba.sentinel.endpoint;
+
+import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider;
+import com.alibaba.csp.sentinel.transport.HeartbeatSender;
+import com.alibaba.csp.sentinel.transport.config.TransportConfig;
+import org.springframework.boot.actuate.health.AbstractHealthIndicator;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.boot.actuate.health.HealthIndicator;
+import org.springframework.boot.actuate.health.Status;
+import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
+import org.springframework.util.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * {@link HealthIndicator} for Sentinel.
+ *
+ * Check the status of Sentinel Dashboard by sending a heartbeat message to it.
+ *
+ * Note: if sentinel isn't enabled or sentinel-dashboard isn't configured,
+ * the health status is up and more infos are provided in detail.
+ *
+ *
+ * @author cdfive
+ */
+public class SentinelHealthIndicator extends AbstractHealthIndicator {
+
+ private SentinelProperties sentinelProperties;
+
+ public SentinelHealthIndicator(SentinelProperties sentinelProperties) {
+ this.sentinelProperties = sentinelProperties;
+ }
+
+ @Override
+ protected void doHealthCheck(Health.Builder builder) throws Exception {
+ Map detailMap = new HashMap<>();
+
+ // If sentinel isn't enabled, set the status up and set the enabled to false in detail
+ if (!sentinelProperties.isEnabled()) {
+ detailMap.put("enabled", false);
+ builder.up().withDetails(detailMap);
+ return;
+ }
+
+ detailMap.put("enabled", true);
+
+ String consoleServer = TransportConfig.getConsoleServer();
+ // If dashboard isn't configured, set the status to UNKNOWN
+ if (StringUtils.isEmpty(consoleServer)) {
+ detailMap.put("dashboard", new Status(Status.UNKNOWN.getCode(), "dashboard isn't configured"));
+ builder.up().withDetails(detailMap);
+ return;
+ }
+
+ // If dashboard is configured, send a heartbeat message to it and check the result
+ HeartbeatSender heartbeatSender = HeartbeatSenderProvider.getHeartbeatSender();
+ boolean result = heartbeatSender.sendHeartbeat();
+ if (result) {
+ detailMap.put("dashboard", Status.UP);
+ builder.up().withDetails(detailMap);
+ } else {
+ detailMap.put("dashboard", new Status(Status.DOWN.getCode(), consoleServer + " can't be connected"));
+ builder.down().withDetails(detailMap);
+ }
+ }
+}
diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicatorTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicatorTests.java
new file mode 100644
index 00000000..7baaf205
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicatorTests.java
@@ -0,0 +1,90 @@
+package org.springframework.cloud.alibaba.sentinel.endpoint;
+
+import com.alibaba.csp.sentinel.config.SentinelConfig;
+import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider;
+import com.alibaba.csp.sentinel.transport.HeartbeatSender;
+import com.alibaba.csp.sentinel.transport.config.TransportConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.boot.actuate.health.Status;
+import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
+import org.springframework.util.ReflectionUtils;
+
+import java.lang.reflect.Field;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Test cases for {@link SentinelHealthIndicator}.
+ *
+ * @author cdfive
+ */
+public class SentinelHealthIndicatorTests {
+
+ private SentinelHealthIndicator sentinelHealthIndicator;
+
+ private SentinelProperties sentinelProperties;
+
+ private HeartbeatSender heartbeatSender;
+
+ @Before
+ public void setUp() {
+ sentinelProperties = mock(SentinelProperties.class);
+ sentinelHealthIndicator = new SentinelHealthIndicator(sentinelProperties);
+
+ SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "");
+
+ heartbeatSender = mock(HeartbeatSender.class);
+ Field heartbeatSenderField = ReflectionUtils.findField(HeartbeatSenderProvider.class, "heartbeatSender");
+ heartbeatSenderField.setAccessible(true);
+ ReflectionUtils.setField(heartbeatSenderField, null, heartbeatSender);
+ }
+
+ @Test
+ public void testSentinelNotEnabled() {
+ when(sentinelProperties.isEnabled()).thenReturn(false);
+
+ Health health = sentinelHealthIndicator.health();
+
+ assertThat(health.getStatus()).isEqualTo(Status.UP);
+ assertThat(health.getDetails().get("enabled")).isEqualTo(false);
+ }
+
+ @Test
+ public void testSentinelDashboardNotConfigured() {
+ when(sentinelProperties.isEnabled()).thenReturn(true);
+
+ Health health = sentinelHealthIndicator.health();
+
+ assertThat(health.getStatus()).isEqualTo(Status.UP);
+ assertThat(health.getDetails().get("dashboard")).isEqualTo(Status.UNKNOWN);
+ }
+
+ @Test
+ public void testSentinelDashboardConfiguredCheckSuccess() throws Exception {
+ when(sentinelProperties.isEnabled()).thenReturn(true);
+ SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "localhost:8080");
+ when(heartbeatSender.sendHeartbeat()).thenReturn(true);
+
+
+ Health health = sentinelHealthIndicator.health();
+
+ assertThat(health.getStatus()).isEqualTo(Status.UP);
+ }
+
+ @Test
+ public void testSentinelDashboardConfiguredCheckFailed() throws Exception {
+ when(sentinelProperties.isEnabled()).thenReturn(true);
+ SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "localhost:8080");
+ when(heartbeatSender.sendHeartbeat()).thenReturn(false);
+
+
+ Health health = sentinelHealthIndicator.health();
+
+ assertThat(health.getStatus()).isEqualTo(Status.DOWN);
+ assertThat(health.getDetails().get("dashboard")).isEqualTo(new Status(Status.DOWN.getCode(), "localhost:8080 can't be connected"));
+ }
+}
From 3e2fa1b903e24f1e2456158ec4185cbeb296a108 Mon Sep 17 00:00:00 2001
From: cdfive <176402936@qq.com>
Date: Sun, 26 May 2019 15:46:39 +0800
Subject: [PATCH 2/4] Fix typo in md files, acutator->
actuator,implmentation->implementation
---
spring-cloud-alibaba-examples/oss-example/readme-zh.md | 2 +-
spring-cloud-alibaba-examples/oss-example/readme.md | 4 ++--
.../sentinel-example/sentinel-core-example/readme-zh.md | 2 +-
spring-cloud-alibaba-examples/sms-example/readme-zh.md | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/spring-cloud-alibaba-examples/oss-example/readme-zh.md b/spring-cloud-alibaba-examples/oss-example/readme-zh.md
index 54cc88d2..bc491e1b 100644
--- a/spring-cloud-alibaba-examples/oss-example/readme-zh.md
+++ b/spring-cloud-alibaba-examples/oss-example/readme-zh.md
@@ -128,7 +128,7 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息,OSS Starter 也
Spring Boot1.x 可以通过访问 http://127.0.0.1:18084/oss 来查看 OSS Endpoint 的信息。
-Spring Boot2.x 可以通过访问 http://127.0.0.1:18084/acutator/oss 来访问。
+Spring Boot2.x 可以通过访问 http://127.0.0.1:18084/actuator/oss 来访问。
Endpoint 内部会显示所有的 OSSClient 配置信息,以及该 OSSClient 对应的 Bucket 列表。
diff --git a/spring-cloud-alibaba-examples/oss-example/readme.md b/spring-cloud-alibaba-examples/oss-example/readme.md
index 11ea77c8..3e5fe291 100644
--- a/spring-cloud-alibaba-examples/oss-example/readme.md
+++ b/spring-cloud-alibaba-examples/oss-example/readme.md
@@ -114,7 +114,7 @@ You can verify results on the OSS console when you finish uploading or downloadi
## Endpoint
-OSS starter also supports the implmentation of Spring Boot acutator endpoints.
+OSS starter also supports the implementation of Spring Boot actuator endpoints.
**Prerequisite:**
@@ -127,7 +127,7 @@ To view the endpoint information, visit the following URLs:
Spring Boot1.x: OSS Endpoint URL is http://127.0.0.1:18084/oss.
-Spring Boot2.x: OSS Endpoint URL is http://127.0.0.1:18084/acutator/oss.
+Spring Boot2.x: OSS Endpoint URL is http://127.0.0.1:18084/actuator/oss.
Endpoint will show the configurations and the list of buckets of all OSSClients.
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md
index bfdc599b..8b3a9214 100644
--- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md
@@ -184,7 +184,7 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息,Sentinel Starter
* Spring Boot 1.x 中添加配置 `management.security.enabled=false`
* Spring Boot 2.x 中添加配置 `management.endpoints.web.exposure.include=*`
-Spring Boot 1.x 可以通过访问 http://127.0.0.1:18083/sentinel 来查看 Sentinel Endpoint 的信息。Spring Boot 2.x 可以通过访问 http://127.0.0.1:18083/acutator/sentinel 来访问。
+Spring Boot 1.x 可以通过访问 http://127.0.0.1:18083/sentinel 来查看 Sentinel Endpoint 的信息。Spring Boot 2.x 可以通过访问 http://127.0.0.1:18083/actuator/sentinel 来访问。

diff --git a/spring-cloud-alibaba-examples/sms-example/readme-zh.md b/spring-cloud-alibaba-examples/sms-example/readme-zh.md
index b21875c9..c07b3608 100644
--- a/spring-cloud-alibaba-examples/sms-example/readme-zh.md
+++ b/spring-cloud-alibaba-examples/sms-example/readme-zh.md
@@ -306,7 +306,7 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息,SMS Starter 也
Spring Boot1.x 可以通过访问 http://127.0.0.1:18084/sms-info 来查看 SMS Endpoint 的信息。
-Spring Boot2.x 可以通过访问 http://127.0.0.1:18084/acutator/sms-info 来访问。
+Spring Boot2.x 可以通过访问 http://127.0.0.1:18084/actuator/sms-info 来访问。
Endpoint 内部会显示最近 20 条单个短信发送的记录和批量短信发送的记录,以及当前短信消息的配置信息(包括是**SmsReport** 还是 **SmsUp**,**队列名称**,以及对应的 **MessageListener** )。
From 584d5f41075d0711f8e6e8736dbd643c535fde04 Mon Sep 17 00:00:00 2001
From: cdfive <176402936@qq.com>
Date: Tue, 28 May 2019 21:53:41 +0800
Subject: [PATCH 3/4] Check the health status of Sentinel DataSource using
AbstractDataSource#loadConfig.
---
.../src/main/resources/application.properties | 4 +
.../SentinelEndpointAutoConfiguration.java | 5 +-
.../endpoint/SentinelHealthIndicator.java | 86 ++++++++++++++++---
...itional-spring-configuration-metadata.json | 6 ++
.../SentinelHealthIndicatorTests.java | 80 ++++++++++++++++-
5 files changed, 162 insertions(+), 19 deletions(-)
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
index 71862fe2..c3d0959d 100644
--- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
@@ -3,6 +3,10 @@ server.port=18083
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
+# we can disable health check, default is enable
+management.health.diskspace.enabled=false
+# management.health.sentinel.enabled=false
+
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
index 7388147a..9af7be97 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
@@ -16,6 +16,7 @@
package org.springframework.cloud.alibaba.sentinel.endpoint;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
@@ -42,7 +43,7 @@ public class SentinelEndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledHealthIndicator("sentinel")
- public SentinelHealthIndicator sentinelHealthIndicator(SentinelProperties sentinelProperties) {
- return new SentinelHealthIndicator(sentinelProperties);
+ public SentinelHealthIndicator sentinelHealthIndicator(DefaultListableBeanFactory beanFactory, SentinelProperties sentinelProperties) {
+ return new SentinelHealthIndicator(beanFactory, sentinelProperties);
}
}
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java
index 82102100..765a3909 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java
@@ -1,8 +1,26 @@
+/*
+ * Copyright (C) 2018 the original author or authors.
+ *
+ * Licensed 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.springframework.cloud.alibaba.sentinel.endpoint;
+import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider;
import com.alibaba.csp.sentinel.transport.HeartbeatSender;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
@@ -14,21 +32,36 @@ import java.util.HashMap;
import java.util.Map;
/**
- * {@link HealthIndicator} for Sentinel.
+ * A {@link HealthIndicator} for Sentinel, which checks the status of
+ * Sentinel Dashboard and DataSource.
+ *
*
* Check the status of Sentinel Dashboard by sending a heartbeat message to it.
+ * If no Exception thrown, it's OK.
*
- * Note: if sentinel isn't enabled or sentinel-dashboard isn't configured,
- * the health status is up and more infos are provided in detail.
+ * Check the status of Sentinel DataSource by calling loadConfig method of {@link AbstractDataSource}.
+ * If return true, it's OK.
+ *
+ * If Dashboard and DataSource are both OK, the health status is UP.
+ *
+ *
+ *
+ * Note:
+ * If Sentinel isn't enabled, the health status is up.
+ * If Sentinel Dashboard isn't configured, it's OK and mark the status of Dashboard with UNKNOWN.
+ * More informations are provided in details.
*
*
* @author cdfive
*/
public class SentinelHealthIndicator extends AbstractHealthIndicator {
+ private DefaultListableBeanFactory beanFactory;
+
private SentinelProperties sentinelProperties;
- public SentinelHealthIndicator(SentinelProperties sentinelProperties) {
+ public SentinelHealthIndicator(DefaultListableBeanFactory beanFactory, SentinelProperties sentinelProperties) {
+ this.beanFactory = beanFactory;
this.sentinelProperties = sentinelProperties;
}
@@ -45,22 +78,49 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator {
detailMap.put("enabled", true);
+ // Check health of Dashboard
+ boolean dashboardUp = true;
String consoleServer = TransportConfig.getConsoleServer();
- // If dashboard isn't configured, set the status to UNKNOWN
if (StringUtils.isEmpty(consoleServer)) {
+ // If Dashboard isn't configured, mark the status of Dashboard with UNKNOWN and the dashboardUp is still true
detailMap.put("dashboard", new Status(Status.UNKNOWN.getCode(), "dashboard isn't configured"));
- builder.up().withDetails(detailMap);
- return;
+ } else {
+ // If Dashboard is configured, send a heartbeat message to it and check the result
+ HeartbeatSender heartbeatSender = HeartbeatSenderProvider.getHeartbeatSender();
+ boolean result = heartbeatSender.sendHeartbeat();
+ if (result) {
+ detailMap.put("dashboard", Status.UP);
+ } else {
+ // If failed to send heartbeat message, means that the Dashboard is DOWN
+ dashboardUp = false;
+ detailMap.put("dashboard", new Status(Status.DOWN.getCode(), consoleServer + " can't be connected"));
+ }
}
- // If dashboard is configured, send a heartbeat message to it and check the result
- HeartbeatSender heartbeatSender = HeartbeatSenderProvider.getHeartbeatSender();
- boolean result = heartbeatSender.sendHeartbeat();
- if (result) {
- detailMap.put("dashboard", Status.UP);
+ // Check health of DataSource
+ boolean dataSourceUp = true;
+ Map dataSourceDetailMap = new HashMap<>();
+ detailMap.put("dataSource", dataSourceDetailMap);
+
+ // Get all DataSources and each call loadConfig to check if it's OK
+ Map dataSourceMap = beanFactory.getBeansOfType(AbstractDataSource.class);
+ for (Map.Entry dataSourceMapEntry : dataSourceMap.entrySet()) {
+ String dataSourceBeanName = dataSourceMapEntry.getKey();
+ AbstractDataSource dataSource = dataSourceMapEntry.getValue();
+ try {
+ dataSource.loadConfig();
+ dataSourceDetailMap.put(dataSourceBeanName, Status.UP);
+ } catch (Exception e) {
+ // If one DataSource failed to loadConfig, means that the DataSource is DOWN
+ dataSourceUp = false;
+ dataSourceDetailMap.put(dataSourceBeanName, new Status(Status.DOWN.getCode(), e.getMessage()));
+ }
+ }
+
+ // If Dashboard and DataSource are both OK, the health status is UP
+ if (dashboardUp && dataSourceUp) {
builder.up().withDetails(detailMap);
} else {
- detailMap.put("dashboard", new Status(Status.DOWN.getCode(), consoleServer + " can't be connected"));
builder.down().withDetails(detailMap);
}
}
diff --git a/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json
index 21713de7..44b0b459 100644
--- a/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ b/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -88,6 +88,12 @@
"type": "java.lang.String",
"defaultValue": "3",
"description": "sentinel the cold factor."
+ },
+ {
+ "name": "management.health.sentinel.enabled",
+ "type": "java.lang.Boolean",
+ "description": "Whether to enable sentinel health check.",
+ "defaultValue": true
}
]
}
diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicatorTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicatorTests.java
index 7baaf205..6245c4a1 100644
--- a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicatorTests.java
+++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicatorTests.java
@@ -1,17 +1,38 @@
+/*
+ * Copyright (C) 2018 the original author or authors.
+ *
+ * Licensed 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.springframework.cloud.alibaba.sentinel.endpoint;
import com.alibaba.csp.sentinel.config.SentinelConfig;
+import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
+import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider;
import com.alibaba.csp.sentinel.transport.HeartbeatSender;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import org.junit.Before;
import org.junit.Test;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status;
import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -26,14 +47,17 @@ public class SentinelHealthIndicatorTests {
private SentinelHealthIndicator sentinelHealthIndicator;
+ private DefaultListableBeanFactory beanFactory;
+
private SentinelProperties sentinelProperties;
private HeartbeatSender heartbeatSender;
@Before
public void setUp() {
+ beanFactory = mock(DefaultListableBeanFactory.class);
sentinelProperties = mock(SentinelProperties.class);
- sentinelHealthIndicator = new SentinelHealthIndicator(sentinelProperties);
+ sentinelHealthIndicator = new SentinelHealthIndicator(beanFactory, sentinelProperties);
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "");
@@ -64,19 +88,18 @@ public class SentinelHealthIndicatorTests {
}
@Test
- public void testSentinelDashboardConfiguredCheckSuccess() throws Exception {
+ public void testSentinelDashboardConfiguredSuccess() throws Exception {
when(sentinelProperties.isEnabled()).thenReturn(true);
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "localhost:8080");
when(heartbeatSender.sendHeartbeat()).thenReturn(true);
-
Health health = sentinelHealthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.UP);
}
@Test
- public void testSentinelDashboardConfiguredCheckFailed() throws Exception {
+ public void testSentinelDashboardConfiguredFailed() throws Exception {
when(sentinelProperties.isEnabled()).thenReturn(true);
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "localhost:8080");
when(heartbeatSender.sendHeartbeat()).thenReturn(false);
@@ -87,4 +110,53 @@ public class SentinelHealthIndicatorTests {
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails().get("dashboard")).isEqualTo(new Status(Status.DOWN.getCode(), "localhost:8080 can't be connected"));
}
+
+ @Test
+ public void testSentinelDataSourceSuccess() throws Exception {
+ when(sentinelProperties.isEnabled()).thenReturn(true);
+ SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "localhost:8080");
+ when(heartbeatSender.sendHeartbeat()).thenReturn(true);
+
+ Map dataSourceMap = new HashMap<>();
+
+ FileRefreshableDataSource fileDataSource1 = mock(FileRefreshableDataSource.class);
+ dataSourceMap.put("ds1-sentinel-file-datasource", fileDataSource1);
+
+ FileRefreshableDataSource fileDataSource2 = mock(FileRefreshableDataSource.class);
+ dataSourceMap.put("ds2-sentinel-file-datasource", fileDataSource2);
+
+ when(beanFactory.getBeansOfType(AbstractDataSource.class)).thenReturn(dataSourceMap);
+
+ Health health = sentinelHealthIndicator.health();
+
+ assertThat(health.getStatus()).isEqualTo(Status.UP);
+ Map dataSourceDetailMap = (Map) health.getDetails().get("dataSource");
+ assertThat(dataSourceDetailMap.get("ds1-sentinel-file-datasource")).isEqualTo(Status.UP);
+ assertThat(dataSourceDetailMap.get("ds2-sentinel-file-datasource")).isEqualTo(Status.UP);
+ }
+
+ @Test
+ public void testSentinelDataSourceFailed() throws Exception {
+ when(sentinelProperties.isEnabled()).thenReturn(true);
+ SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "localhost:8080");
+ when(heartbeatSender.sendHeartbeat()).thenReturn(true);
+
+ Map dataSourceMap = new HashMap<>();
+
+ FileRefreshableDataSource fileDataSource1 = mock(FileRefreshableDataSource.class);
+ dataSourceMap.put("ds1-sentinel-file-datasource", fileDataSource1);
+
+ FileRefreshableDataSource fileDataSource2 = mock(FileRefreshableDataSource.class);
+ when(fileDataSource2.loadConfig()).thenThrow(new RuntimeException("fileDataSource2 error"));
+ dataSourceMap.put("ds2-sentinel-file-datasource", fileDataSource2);
+
+ when(beanFactory.getBeansOfType(AbstractDataSource.class)).thenReturn(dataSourceMap);
+
+ Health health = sentinelHealthIndicator.health();
+
+ assertThat(health.getStatus()).isEqualTo(Status.DOWN);
+ Map dataSourceDetailMap = (Map) health.getDetails().get("dataSource");
+ assertThat(dataSourceDetailMap.get("ds1-sentinel-file-datasource")).isEqualTo(Status.UP);
+ assertThat(dataSourceDetailMap.get("ds2-sentinel-file-datasource")).isEqualTo(new Status(Status.DOWN.getCode(), "fileDataSource2 error"));
+ }
}
From a0a4bb050797ac729985841cf44a67a2d70ae054 Mon Sep 17 00:00:00 2001
From: cdfive <176402936@qq.com>
Date: Wed, 29 May 2019 12:38:27 +0800
Subject: [PATCH 4/4] Fix error comment and add note comment for checking
dataSource.
---
.../sentinel/endpoint/SentinelHealthIndicator.java | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java
index 765a3909..8ca863ab 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java
@@ -37,10 +37,10 @@ import java.util.Map;
*
*
* Check the status of Sentinel Dashboard by sending a heartbeat message to it.
- * If no Exception thrown, it's OK.
+ * If return true, it's OK.
*
* Check the status of Sentinel DataSource by calling loadConfig method of {@link AbstractDataSource}.
- * If return true, it's OK.
+ * If no Exception thrown, it's OK.
*
* If Dashboard and DataSource are both OK, the health status is UP.
*
@@ -82,7 +82,7 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator {
boolean dashboardUp = true;
String consoleServer = TransportConfig.getConsoleServer();
if (StringUtils.isEmpty(consoleServer)) {
- // If Dashboard isn't configured, mark the status of Dashboard with UNKNOWN and the dashboardUp is still true
+ // If Dashboard isn't configured, it's OK and mark the status of Dashboard with UNKNOWN.
detailMap.put("dashboard", new Status(Status.UNKNOWN.getCode(), "dashboard isn't configured"));
} else {
// If Dashboard is configured, send a heartbeat message to it and check the result
@@ -103,6 +103,11 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator {
detailMap.put("dataSource", dataSourceDetailMap);
// Get all DataSources and each call loadConfig to check if it's OK
+ // If no Exception thrown, it's OK
+ // Note:
+ // Even if the dynamic config center is down, the loadConfig() might return successfully
+ // e.g. for Nacos client, it might retrieve from the local cache)
+ // But in most circumstances it's okay
Map dataSourceMap = beanFactory.getBeansOfType(AbstractDataSource.class);
for (Map.Entry dataSourceMapEntry : dataSourceMap.entrySet()) {
String dataSourceBeanName = dataSourceMapEntry.getKey();