Skip to content

Commit 54b83e0

Browse files
committed
health service for actuator
1 parent 3dec710 commit 54b83e0

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package net.devh.boot.grpc.server.health;
2+
3+
import io.grpc.Status;
4+
import io.grpc.StatusException;
5+
import io.grpc.health.v1.HealthCheckRequest;
6+
import io.grpc.health.v1.HealthCheckResponse;
7+
import io.grpc.health.v1.HealthGrpc;
8+
import io.grpc.stub.StreamObserver;
9+
import org.springframework.boot.actuate.health.HealthEndpoint;
10+
11+
import java.util.Objects;
12+
13+
public class ActuatorGrpcHealth extends HealthGrpc.HealthImplBase {
14+
private final HealthEndpoint healthEndpoint;
15+
16+
public ActuatorGrpcHealth(HealthEndpoint healthEndpoint) {
17+
this.healthEndpoint = healthEndpoint;
18+
}
19+
20+
public void check(HealthCheckRequest request, StreamObserver<HealthCheckResponse> responseObserver) {
21+
22+
if (!request.getService().isEmpty()) {
23+
var health = healthEndpoint.healthForPath(request.getService());
24+
if(health == null) {
25+
responseObserver.onError(new StatusException(Status.NOT_FOUND.withDescription("unknown service " + request.getService())));
26+
return;
27+
}
28+
var status = health.getStatus();
29+
HealthCheckResponse.ServingStatus result = resolveStatus(status);
30+
HealthCheckResponse response = HealthCheckResponse.newBuilder().setStatus(result).build();
31+
responseObserver.onNext(response);
32+
responseObserver.onCompleted();
33+
} else {
34+
35+
var status = healthEndpoint.health().getStatus();
36+
HealthCheckResponse.ServingStatus result = resolveStatus(status);
37+
HealthCheckResponse response = HealthCheckResponse.newBuilder().setStatus(result).build();
38+
responseObserver.onNext(response);
39+
responseObserver.onCompleted();
40+
}
41+
42+
}
43+
44+
private HealthCheckResponse.ServingStatus resolveStatus(org.springframework.boot.actuate.health.Status status) {
45+
if (Objects.equals(org.springframework.boot.actuate.health.Status.UP.getCode(), status.getCode())) {
46+
return HealthCheckResponse.ServingStatus.SERVING;
47+
}
48+
if (Objects.equals(org.springframework.boot.actuate.health.Status.DOWN.getCode(), status.getCode()) || Objects.equals(org.springframework.boot.actuate.health.Status.OUT_OF_SERVICE.getCode(), status.getCode())) {
49+
return HealthCheckResponse.ServingStatus.NOT_SERVING;
50+
}
51+
return HealthCheckResponse.ServingStatus.UNKNOWN;
52+
}
53+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package net.devh.boot.grpc.server.health;
2+
3+
import io.grpc.StatusException;
4+
import io.grpc.health.v1.HealthCheckRequest;
5+
import io.grpc.health.v1.HealthCheckResponse;
6+
import io.grpc.internal.testing.StreamRecorder;
7+
import org.junit.jupiter.api.BeforeEach;
8+
import org.junit.jupiter.api.Test;
9+
import org.junit.jupiter.api.extension.ExtendWith;
10+
import org.mockito.Mock;
11+
import org.mockito.junit.jupiter.MockitoExtension;
12+
import org.springframework.boot.actuate.health.Health;
13+
import org.springframework.boot.actuate.health.HealthComponent;
14+
import org.springframework.boot.actuate.health.HealthEndpoint;
15+
16+
import java.util.List;
17+
18+
import static org.junit.jupiter.api.Assertions.*;
19+
import static org.mockito.Mockito.when;
20+
21+
@ExtendWith(MockitoExtension.class)
22+
class ActuatorGrpcHealthTest {
23+
@Mock
24+
HealthEndpoint healthEndpoint;
25+
26+
ActuatorGrpcHealth server;
27+
28+
@BeforeEach
29+
public void setup() {
30+
this.server = new ActuatorGrpcHealth(healthEndpoint);
31+
}
32+
33+
34+
@Test
35+
void testDefaultServiceWorking() {
36+
StreamRecorder<HealthCheckResponse> response = StreamRecorder.create();
37+
HealthCheckRequest request = HealthCheckRequest.newBuilder().setService("").build();
38+
39+
HealthComponent healthResult = Health.up().build();
40+
41+
when(healthEndpoint.health())
42+
.thenReturn(healthResult);
43+
44+
server.check(request, response);
45+
46+
List<HealthCheckResponse> result = response.getValues();
47+
assertEquals(1, result.size());
48+
assertEquals(HealthCheckResponse.ServingStatus.SERVING, result.get(0).getStatus());
49+
}
50+
51+
@Test
52+
void testDefaultServiceNotWorking() {
53+
StreamRecorder<HealthCheckResponse> response = StreamRecorder.create();
54+
HealthCheckRequest request = HealthCheckRequest.newBuilder().setService("").build();
55+
56+
HealthComponent healthResult = Health.down().build();
57+
58+
when(healthEndpoint.health())
59+
.thenReturn(healthResult);
60+
61+
server.check(request, response);
62+
63+
List<HealthCheckResponse> result = response.getValues();
64+
65+
assertEquals(1, result.size());
66+
67+
assertEquals(HealthCheckResponse.ServingStatus.NOT_SERVING, result.get(0).getStatus());
68+
}
69+
70+
@Test
71+
void testSpecificServiceNotFound() {
72+
StreamRecorder<HealthCheckResponse> response = StreamRecorder.create();
73+
HealthCheckRequest request = HealthCheckRequest.newBuilder().setService("someunknownservice").build();
74+
75+
when(healthEndpoint.healthForPath("someunknownservice"))
76+
.thenReturn(null);
77+
78+
server.check(request, response);
79+
80+
assertEquals(0, response.getValues().size());
81+
82+
var error = response.getError();
83+
assertNotNull(error);
84+
assertInstanceOf(StatusException.class, error);
85+
86+
var statusException = (StatusException) error;
87+
assertEquals(io.grpc.Status.NOT_FOUND.getCode(), statusException.getStatus().getCode());
88+
}
89+
90+
@Test
91+
void testSpecificServiceUp() {
92+
StreamRecorder<HealthCheckResponse> response = StreamRecorder.create();
93+
HealthCheckRequest request = HealthCheckRequest.newBuilder().setService("db").build();
94+
95+
HealthComponent healthResult = Health.up().build();
96+
when(healthEndpoint.healthForPath("db"))
97+
.thenReturn(healthResult);
98+
99+
server.check(request, response);
100+
101+
List<HealthCheckResponse> result = response.getValues();
102+
assertEquals(1, result.size());
103+
assertEquals(HealthCheckResponse.ServingStatus.SERVING, result.get(0).getStatus());
104+
}
105+
106+
}

0 commit comments

Comments
 (0)