Skip to content

Commit c2b1294

Browse files
Servicebus health indicator implementation and doc. (Azure#23050)
* Add health indicator doc. * Service bus health indicator logic implementation. * Add unit tests.
1 parent ee215fc commit c2b1294

File tree

32 files changed

+689
-31
lines changed

32 files changed

+689
-31
lines changed

sdk/spring/azure-spring-boot/README.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,97 @@ variable and setting the appropriate properties used by auto-configuration code.
3434

3535
For details, please see sample code in the [azure-spring-boot-sample-cloud-foundry](https://github.com/Azure-Samples/azure-spring-boot-samples/tree/tag_azure-spring-boot_3.6.0/cloudfoundry/azure-cloud-foundry-service-sample)
3636

37+
## Health indicator
38+
39+
You can use health information to check the status of your running application. It is often used by
40+
monitoring software to alert someone when a production system goes down. The information exposed by
41+
the health endpoint depends on the management.endpoint.health.show-details and
42+
management.endpoint.health.show-components properties which can be configured with one of the
43+
following values:
44+
45+
| key | Name |
46+
| ---- | ---- |
47+
| never | Details are never shown. |
48+
| when-authorized | Details are only shown to authorized users. Authorized roles can be configured using management.endpoint.health.roles. |
49+
| always |Details are shown to all users. |
50+
51+
The default value is never. A user is considered to be authorized when they are in one or more of
52+
the endpoint’s roles. If the endpoint has no configured roles (the default) all authenticated users
53+
are considered to be authorized. The roles can be configured using the
54+
management.endpoint.health.roles property.
55+
56+
**NOTE:** If you have secured your application and wish to use `always`, your security configuration
57+
must permit access to the health endpoint for both authenticated and unauthenticated users.
58+
59+
### Auto-configured HealthIndicators
60+
61+
The following HealthIndicators are auto-configured by Azure Spring Boot when appropriate. You can
62+
also enable/disable selected indicators by configuring management.health.key.enabled, with the key
63+
listed in the table below.
64+
65+
| key | Name | Description |
66+
| ---- | ---- | ---- |
67+
| azure-cosmos | CosmosHealthIndicator | Checks that a cosmos database is up. |
68+
| azure-key-vault | KeyVaultHealthIndicator | Checks that a key vault is up. |
69+
| azure-storage | BlobStorageHealthIndicator | Checks that a storage blob is up. |
70+
| azure-storage | FileStorageHealthIndicator | Checks that a storage file is up. |
71+
72+
### Add the dependent
73+
74+
```yaml
75+
<dependencies>
76+
<dependency>
77+
<groupId>org.springframework.boot</groupId>
78+
<artifactId>spring-boot-starter-actuator</artifactId>
79+
</dependency>
80+
</dependencies>
81+
```
82+
83+
### Enabling the Actuator
84+
85+
When you do the following configuration in `application.yml` , you can access the endpoint to get
86+
the health of the component.
87+
88+
```yaml
89+
management:
90+
health:
91+
azure-cosmos:
92+
enabled: true
93+
azure-key-vault:
94+
enabled: true
95+
azure-storage:
96+
enabled: true
97+
endpoint:
98+
health:
99+
show-details: always
100+
```
101+
102+
Access the Health Endpoint:
103+
104+
```json
105+
{
106+
"status": "UP",
107+
"components": {
108+
"blobStorage": {
109+
"status": "UP",
110+
"details": {
111+
"URL": "https://xxxx.blob.core.windows.net"
112+
}
113+
},
114+
"cosmos": {
115+
"status": "UP",
116+
"details": {
117+
"database": "xxx"
118+
}
119+
},
120+
"keyVault": {
121+
"status": "UP"
122+
}
123+
}
124+
}
125+
```
126+
127+
37128
## Examples
38129
The following section provides sample projects illustrating how to use the Azure Spring Boot starters.
39130
### More sample code

sdk/spring/azure-spring-cloud-autoconfigure/README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,87 @@ This project provides auto-configuration for the following Azure services:
2828
- [Service Bus][service_bus]
2929
- [Storage Queue][storage_queue]
3030

31+
## Health indicator
32+
33+
You can use health information to check the status of your running application. It is often used by
34+
monitoring software to alert someone when a production system goes down. The information exposed by
35+
the health endpoint depends on the management.endpoint.health.show-details and
36+
management.endpoint.health.show-components properties which can be configured with one of the
37+
following values:
38+
39+
| key | Name |
40+
| ---- | ---- |
41+
| never | Details are never shown. |
42+
| when-authorized | Details are only shown to authorized users. Authorized roles can be configured using management.endpoint.health.roles. |
43+
| always |Details are shown to all users. |
44+
45+
The default value is never. A user is considered to be authorized when they are in one or more of
46+
the endpoint’s roles. If the endpoint has no configured roles (the default) all authenticated users
47+
are considered to be authorized. The roles can be configured using the
48+
management.endpoint.health.roles property.
49+
50+
**NOTE:** If you have secured your application and wish to use `always`, your security configuration
51+
must permit access to the health endpoint for both authenticated and unauthenticated users.
52+
53+
### Auto-configured HealthIndicators
54+
55+
The following HealthIndicators are auto-configured by Azure Spring Boot when appropriate. You can
56+
also enable/disable selected indicators by configuring management.health.key.enabled, with the key
57+
listed in the table below.
58+
59+
| key | Name | Description |
60+
| ---- | ---- | ---- |
61+
| binders | EventHubHealthIndicator | Checks that an event hub is up. |
62+
| binders | ServiceBusQueueHealthIndicator | Checks that a service bus queue is up. |
63+
| binders | ServiceBusTopicHealthIndicator | Checks that a service bus topic is up. |
64+
65+
### Add the dependent
66+
67+
```yaml
68+
<dependencies>
69+
<dependency>
70+
<groupId>org.springframework.boot</groupId>
71+
<artifactId>spring-boot-starter-actuator</artifactId>
72+
</dependency>
73+
</dependencies>
74+
```
75+
76+
### Enabling the Actuator
77+
78+
When you do the following configuration in `application.yml` , you can access the endpoint to get
79+
the health of the component.
80+
81+
```yaml
82+
management:
83+
health:
84+
binders:
85+
enabled: true
86+
endpoint:
87+
health:
88+
show-details: always
89+
```
90+
91+
Access the Health Endpoint:
92+
93+
```json
94+
{
95+
"status": "UP",
96+
"components": {
97+
"binders": {
98+
"status": "UP",
99+
"components": {
100+
"eventhub-1": {
101+
"status": "UP"
102+
},
103+
"servicebus-1": {
104+
"status": "UP"
105+
}
106+
}
107+
}
108+
}
109+
}
110+
```
111+
31112
## Examples
32113

33114
The following section provides sample projects illustrating how to use the Spring Cloud for Azure starters.

sdk/spring/azure-spring-cloud-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/servicebus/AzureServiceBusAutoConfiguration.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,4 @@ public ServiceBusConnectionStringProvider serviceBusConnectionStringProvider(
7676

7777
return null;
7878
}
79-
8079
}

sdk/spring/azure-spring-cloud-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/servicebus/AzureServiceBusTopicAutoConfiguration.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,4 @@ public ServiceBusTopicOperation topicOperation(ServiceBusTopicClientFactory fact
9494
ServiceBusMessageConverter messageConverter) {
9595
return new ServiceBusTopicTemplate(factory, messageConverter);
9696
}
97-
9897
}

sdk/spring/azure-spring-cloud-stream-binder-servicebus-queue/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@
3737
<optional>true</optional>
3838
</dependency>
3939

40+
<dependency>
41+
<groupId>org.springframework.boot</groupId>
42+
<artifactId>spring-boot-starter-actuator</artifactId>
43+
<version>2.5.3</version> <!-- {x-version-update;org.springframework.boot:spring-boot-starter-actuator;external_dependency} -->
44+
<optional>true</optional>
45+
</dependency>
46+
4047
<dependency>
4148
<groupId>com.azure.spring</groupId>
4249
<artifactId>azure-spring-cloud-stream-binder-test</artifactId>
@@ -65,6 +72,7 @@
6572
<bannedDependencies>
6673
<includes>
6774
<include>org.springframework.boot:spring-boot-configuration-processor:[2.5.3]</include> <!-- {x-include-update;org.springframework.boot:spring-boot-configuration-processor;external_dependency} -->
75+
<include>org.springframework.boot:spring-boot-starter-actuator:[2.5.3]</include> <!-- {x-include-update;org.springframework.boot:spring-boot-starter-actuator;external_dependency} -->
6876
</includes>
6977
</bannedDependencies>
7078
</rules>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
package com.azure.spring.servicebus.stream.binder;
4+
5+
import com.azure.spring.integration.servicebus.health.Instrumentation;
6+
import com.azure.spring.integration.servicebus.health.InstrumentationManager;
7+
import com.azure.spring.integration.servicebus.queue.ServiceBusQueueOperation;
8+
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
9+
import org.springframework.boot.actuate.health.Health;
10+
11+
/**
12+
* Implementation of a {@link AbstractHealthIndicator} returning status information for
13+
* service bus queue.
14+
*/
15+
public class ServiceBusQueueHealthIndicator extends AbstractHealthIndicator {
16+
17+
private final InstrumentationManager instrumentationManager;
18+
19+
public ServiceBusQueueHealthIndicator(ServiceBusQueueOperation serviceBusQueueOperation) {
20+
super("Service bus health check failed");
21+
this.instrumentationManager = serviceBusQueueOperation.getInstrumentationManager();
22+
}
23+
24+
@Override
25+
protected void doHealthCheck(Health.Builder builder) {
26+
if (instrumentationManager == null || instrumentationManager.getHealthInstrumentations().isEmpty()) {
27+
builder.unknown();
28+
return;
29+
}
30+
if (instrumentationManager.getHealthInstrumentations().stream()
31+
.allMatch(Instrumentation::isUp)) {
32+
builder.up();
33+
return;
34+
}
35+
if (instrumentationManager.getHealthInstrumentations().stream()
36+
.allMatch(Instrumentation::isOutOfService)) {
37+
builder.outOfService();
38+
return;
39+
}
40+
builder.down();
41+
instrumentationManager.getHealthInstrumentations().stream()
42+
.filter(instrumentation -> !instrumentation.isStarted())
43+
.forEach(instrumentation -> builder
44+
.withDetail(instrumentation.getName() + ":" + instrumentation.getType().getTypeName(),
45+
instrumentation.getStartException()));
46+
}
47+
}

sdk/spring/azure-spring-cloud-stream-binder-servicebus-queue/src/main/java/com/azure/spring/servicebus/stream/binder/config/ServiceBusQueueBinderConfiguration.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232
AzureEnvironmentAutoConfiguration.class,
3333
AzureContextAutoConfiguration.class,
3434
AzureServiceBusAutoConfiguration.class,
35-
AzureServiceBusQueueAutoConfiguration.class })
35+
AzureServiceBusQueueAutoConfiguration.class,
36+
ServiceBusQueueBinderHealthIndicatorConfiguration.class
37+
})
3638
@EnableConfigurationProperties({ AzureServiceBusProperties.class, ServiceBusQueueExtendedBindingProperties.class })
3739
public class ServiceBusQueueBinderConfiguration {
3840

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
package com.azure.spring.servicebus.stream.binder.config;
4+
5+
import com.azure.spring.integration.servicebus.queue.ServiceBusQueueOperation;
6+
import com.azure.spring.servicebus.stream.binder.ServiceBusQueueHealthIndicator;
7+
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
8+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
9+
import org.springframework.context.annotation.Bean;
10+
import org.springframework.context.annotation.Configuration;
11+
12+
/**
13+
* Auto configuration for {@link ServiceBusQueueHealthIndicator}.
14+
*/
15+
@Configuration
16+
@ConditionalOnClass(name = "org.springframework.boot.actuate.health.HealthIndicator")
17+
@ConditionalOnEnabledHealthIndicator("binders")
18+
public class ServiceBusQueueBinderHealthIndicatorConfiguration {
19+
20+
@Bean
21+
public ServiceBusQueueHealthIndicator serviceBusQueueHealthIndicator(ServiceBusQueueOperation serviceBusQueueOperation) {
22+
return new ServiceBusQueueHealthIndicator(serviceBusQueueOperation);
23+
}
24+
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.spring.servicebus.stream.binder;
5+
6+
import com.azure.messaging.servicebus.ServiceBusProcessorClient;
7+
import com.azure.spring.integration.servicebus.ServiceBusClientConfig;
8+
import com.azure.spring.integration.servicebus.ServiceBusMessageProcessor;
9+
import com.azure.spring.integration.servicebus.ServiceBusRuntimeException;
10+
import com.azure.spring.integration.servicebus.factory.ServiceBusQueueClientFactory;
11+
import com.azure.spring.integration.servicebus.queue.ServiceBusQueueTemplate;
12+
import org.junit.jupiter.api.BeforeEach;
13+
import org.junit.jupiter.api.Test;
14+
import org.mockito.Mock;
15+
import org.mockito.MockitoAnnotations;
16+
import org.springframework.boot.actuate.health.Health;
17+
import org.springframework.boot.actuate.health.Status;
18+
import org.springframework.messaging.Message;
19+
20+
import java.util.function.Consumer;
21+
22+
import static org.assertj.core.api.Assertions.assertThat;
23+
import static org.junit.jupiter.api.Assertions.assertThrows;
24+
import static org.mockito.ArgumentMatchers.any;
25+
import static org.mockito.ArgumentMatchers.anyString;
26+
import static org.mockito.Mockito.doThrow;
27+
import static org.mockito.Mockito.when;
28+
29+
public class ServiceBusQueueBinderHealthIndicatorTest {
30+
31+
@Mock
32+
private ServiceBusQueueClientFactory serviceBusQueueClientFactory;
33+
34+
@Mock
35+
private ServiceBusProcessorClient processorClient;
36+
37+
private ServiceBusQueueHealthIndicator serviceBusQueueHealthIndicator;
38+
39+
private ServiceBusQueueTemplate serviceBusQueueTemplate;
40+
41+
private Consumer<Message<?>> consumer = message -> {
42+
};
43+
44+
@BeforeEach
45+
public void init() {
46+
MockitoAnnotations.openMocks(this);
47+
serviceBusQueueTemplate = new ServiceBusQueueTemplate(serviceBusQueueClientFactory);
48+
serviceBusQueueHealthIndicator = new ServiceBusQueueHealthIndicator(serviceBusQueueTemplate);
49+
}
50+
51+
@Test
52+
public void testNoInstrumentationInUse() {
53+
final Health health = serviceBusQueueHealthIndicator.health();
54+
assertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);
55+
}
56+
57+
@SuppressWarnings({ "unchecked", "rawtypes" })
58+
@Test
59+
public void testServiceBusQueueIsUp() {
60+
when(serviceBusQueueClientFactory.getOrCreateProcessor(anyString(), any(ServiceBusClientConfig.class),
61+
any(ServiceBusMessageProcessor.class))).thenReturn(processorClient);
62+
serviceBusQueueTemplate.subscribe("queue-test-1", consumer, byte[].class);
63+
final Health health = serviceBusQueueHealthIndicator.health();
64+
assertThat(health.getStatus()).isEqualTo(Status.UP);
65+
}
66+
67+
@SuppressWarnings({ "unchecked", "rawtypes" })
68+
@Test
69+
public void testServiceBusQueueIsDown() {
70+
when(serviceBusQueueClientFactory.getOrCreateProcessor(anyString(), any(ServiceBusClientConfig.class),
71+
any(ServiceBusMessageProcessor.class))).thenReturn(processorClient);
72+
doThrow(NullPointerException.class).when(processorClient).start();
73+
assertThrows(ServiceBusRuntimeException.class, () -> {
74+
serviceBusQueueTemplate.subscribe("queue-test-1", consumer, byte[].class);
75+
});
76+
final Health health = serviceBusQueueHealthIndicator.health();
77+
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
78+
}
79+
80+
}

sdk/spring/azure-spring-cloud-stream-binder-servicebus-queue/src/test/java/com/azure/spring/servicebus/stream/binder/ServiceBusQueuePartitionBinderTests.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@
2424
@RunWith(MockitoJUnitRunner.class)
2525
public class ServiceBusQueuePartitionBinderTests
2626
extends AzurePartitionBinderTests<ServiceBusQueueTestBinder,
27-
ExtendedConsumerProperties<ServiceBusConsumerProperties>,
28-
ExtendedProducerProperties<ServiceBusProducerProperties>> {
29-
//TODO (Xiaobing Zhu): It is currently impossible to upgrade JUnit 4 to JUnit 5 due to the inheritance of Spring unit tests.
27+
ExtendedConsumerProperties<ServiceBusConsumerProperties>,
28+
ExtendedProducerProperties<ServiceBusProducerProperties>> {
29+
//TODO (Xiaobing Zhu): It is currently impossible to upgrade JUnit 4 to JUnit 5 due to the inheritance of Spring
30+
// unit tests.
3031

3132
@Mock
3233
ServiceBusQueueClientFactory clientFactory;

0 commit comments

Comments
 (0)