Skip to content

Commit 03248ac

Browse files
author
Alexander Furer
committed
Make HealthGrpc.HealthImplBase a @GRpcService compatible (#242)
1 parent ae72e98 commit 03248ac

File tree

6 files changed

+78
-56
lines changed

6 files changed

+78
-56
lines changed
Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
import io.grpc.health.v1.HealthGrpc;
77
import org.junit.Test;
88
import org.junit.runner.RunWith;
9+
import org.lognet.springboot.grpc.GRpcService;
910
import org.lognet.springboot.grpc.GrpcServerTestBase;
1011
import org.lognet.springboot.grpc.demo.DemoApp;
11-
import org.springframework.beans.factory.annotation.Autowired;
12+
import org.mockito.Mockito;
1213
import org.springframework.boot.test.context.SpringBootTest;
1314
import org.springframework.boot.test.context.TestConfiguration;
14-
import org.springframework.context.annotation.Bean;
15+
import org.springframework.boot.test.mock.mockito.SpyBean;
1516
import org.springframework.test.context.ActiveProfiles;
1617
import org.springframework.test.context.junit4.SpringRunner;
1718

@@ -23,24 +24,22 @@
2324
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
2425

2526
@RunWith(SpringRunner.class)
26-
@SpringBootTest(classes = {DemoApp.class, CustomGRpcHealthStatusManagerTest.Cfg.class}, webEnvironment = NONE)
27+
@SpringBootTest(classes = {DemoApp.class, CustomManagedHealthStatusServiceTest.Cfg.class}, webEnvironment = NONE)
2728
@ActiveProfiles("disable-security")
28-
public class CustomGRpcHealthStatusManagerTest extends GrpcServerTestBase {
29+
public class CustomManagedHealthStatusServiceTest extends GrpcServerTestBase {
2930
@TestConfiguration
3031
static class Cfg{
31-
static class MyCustomHealthStatusManager extends DefaultHealthStatusManager{}
32-
@Bean
33-
public GRpcHealthStatusManager myCustom(){
34-
return new MyCustomHealthStatusManager();
35-
}
32+
@GRpcService
33+
static class MyCustomHealthStatusService extends DefaultHealthStatusService {}
34+
3635
}
3736

38-
@Autowired
39-
private GRpcHealthStatusManager healthStatusManager;
37+
@SpyBean
38+
private ManagedHealthStatusService healthStatusManager;
4039

4140
@Test
4241
public void contextLoads() {
43-
assertThat(healthStatusManager,isA(Cfg.MyCustomHealthStatusManager.class));
42+
assertThat(healthStatusManager,isA(Cfg.MyCustomHealthStatusService.class));
4443
}
4544

4645
@Test
@@ -50,5 +49,8 @@ public void testHealthCheck() throws ExecutionException, InterruptedException {
5049
final HealthCheckResponse.ServingStatus servingStatus = healthFutureStub.check(healthCheckRequest).get().getStatus();
5150

5251
assertThat(servingStatus, is(HealthCheckResponse.ServingStatus.SERVING));
52+
53+
Mockito.verify(healthStatusManager,Mockito.atLeast(1))
54+
.setStatus(Mockito.any(String.class),Mockito.eq(HealthCheckResponse.ServingStatus.SERVING));
5355
}
5456
}

grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/GRpcServerRunner.java

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
import io.grpc.ServerInterceptors;
88
import io.grpc.ServerServiceDefinition;
99
import io.grpc.health.v1.HealthCheckResponse;
10+
import io.grpc.health.v1.HealthGrpc;
1011
import io.grpc.protobuf.services.ProtoReflectionService;
1112
import lombok.extern.slf4j.Slf4j;
1213
import org.lognet.springboot.grpc.autoconfigure.GRpcServerProperties;
1314
import org.lognet.springboot.grpc.context.GRpcServerInitializedEvent;
14-
import org.lognet.springboot.grpc.health.GRpcHealthStatusManager;
15+
import org.lognet.springboot.grpc.health.ManagedHealthStatusService;
16+
import org.springframework.beans.FatalBeanException;
1517
import org.springframework.beans.factory.BeanCreationException;
1618
import org.springframework.beans.factory.annotation.Autowired;
1719
import org.springframework.beans.factory.config.BeanDefinition;
@@ -42,8 +44,8 @@
4244
public class GRpcServerRunner implements SmartLifecycle {
4345

4446
private final AtomicBoolean isRunning = new AtomicBoolean(false);
45-
@Autowired
46-
private Optional<GRpcHealthStatusManager> healthStatusManager;
47+
48+
private Optional<ManagedHealthStatusService> healthStatusManager = Optional.empty();
4749

4850
@Autowired
4951
private AbstractApplicationContext applicationContext;
@@ -77,28 +79,39 @@ public void start() {
7779
.map(name -> applicationContext.getBeanFactory().getBean(name, ServerInterceptor.class))
7880
.collect(Collectors.toList());
7981

80-
// Adding health service
81-
healthStatusManager
82-
.map(GRpcHealthStatusManager::getHealthService)
83-
.ifPresent(serverBuilder::addService);
8482

8583
// find and register all GRpcService-enabled beans
84+
List<String> serviceNames = new ArrayList<>();
8685
getBeanNamesByTypeWithAnnotation(GRpcService.class, BindableService.class)
8786
.forEach(name -> {
8887
BindableService srv = applicationContext.getBeanFactory().getBean(name, BindableService.class);
8988
ServerServiceDefinition serviceDefinition = srv.bindService();
9089
GRpcService gRpcServiceAnn = applicationContext.findAnnotationOnBean(name, GRpcService.class);
9190
serviceDefinition = bindInterceptors(serviceDefinition, gRpcServiceAnn, globalInterceptors);
9291
serverBuilder.addService(serviceDefinition);
93-
String serviceName = serviceDefinition.getServiceDescriptor().getName();
94-
healthStatusManager.ifPresent(m ->
95-
m.setStatus(serviceName, HealthCheckResponse.ServingStatus.SERVING)
96-
);
92+
93+
if (srv instanceof HealthGrpc.HealthImplBase) {
94+
if(!(srv instanceof ManagedHealthStatusService)){
95+
throw new FatalBeanException(String.format("Please inherit %s from %s rather than directly from %s",
96+
srv.getClass().getName(),
97+
ManagedHealthStatusService.class.getName(),
98+
HealthGrpc.HealthImplBase.class.getName()
99+
));
100+
}
101+
healthStatusManager = Optional.of((ManagedHealthStatusService)srv);
102+
} else {
103+
serviceNames.add(serviceDefinition.getServiceDescriptor().getName());
104+
}
105+
97106

98107
log.info("'{}' service has been registered.", srv.getClass().getName());
99108

100109
});
101110

111+
healthStatusManager.ifPresent(h ->
112+
serviceNames.forEach(serviceName -> h.setStatus(serviceName, HealthCheckResponse.ServingStatus.SERVING))
113+
);
114+
102115
if (gRpcServerProperties.isEnableReflection()) {
103116
serverBuilder.addService(ProtoReflectionService.newInstance());
104117
log.info("'{}' service has been registered.", ProtoReflectionService.class.getName());
@@ -180,7 +193,7 @@ private void startDaemonAwaitThread() {
180193
public void stop() {
181194
Optional.ofNullable(server).ifPresent(s -> {
182195
log.info("Shutting down gRPC server ...");
183-
healthStatusManager.ifPresent(GRpcHealthStatusManager::onShutdown);
196+
healthStatusManager.ifPresent(ManagedHealthStatusService::onShutdown);
184197

185198
s.shutdown();
186199
int shutdownGrace = gRpcServerProperties.getShutdownGrace();

grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/autoconfigure/GRpcAutoConfiguration.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import org.lognet.springboot.grpc.GRpcServerBuilderConfigurer;
66
import org.lognet.springboot.grpc.GRpcServerRunner;
77
import org.lognet.springboot.grpc.GRpcService;
8-
import org.lognet.springboot.grpc.health.DefaultHealthStatusManager;
9-
import org.lognet.springboot.grpc.health.GRpcHealthStatusManager;
8+
import org.lognet.springboot.grpc.health.DefaultHealthStatusService;
9+
import org.lognet.springboot.grpc.health.ManagedHealthStatusService;
1010
import org.springframework.beans.factory.BeanCreationException;
1111
import org.springframework.beans.factory.annotation.Autowired;
1212
import org.springframework.beans.factory.annotation.Qualifier;
@@ -60,8 +60,8 @@ public GRpcServerRunner grpcInprocessServerRunner(@Qualifier("grpcInternalConfig
6060

6161
@Bean
6262
@ConditionalOnMissingBean
63-
public GRpcHealthStatusManager healthStatusManager() {
64-
return new DefaultHealthStatusManager();
63+
public ManagedHealthStatusService healthStatusManager() {
64+
return new DefaultHealthStatusService();
6565
}
6666

6767
@Bean

grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/health/DefaultHealthStatusManager.java

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.lognet.springboot.grpc.health;
2+
3+
import io.grpc.health.v1.HealthCheckRequest;
4+
import io.grpc.health.v1.HealthCheckResponse;
5+
import io.grpc.health.v1.HealthGrpc;
6+
import io.grpc.protobuf.services.HealthStatusManager;
7+
import io.grpc.stub.StreamObserver;
8+
9+
public class DefaultHealthStatusService extends ManagedHealthStatusService {
10+
private final HealthStatusManager healthStatusManager = new HealthStatusManager();
11+
private final HealthGrpc.HealthImplBase service = (HealthGrpc.HealthImplBase) healthStatusManager.getHealthService();
12+
13+
@Override
14+
public void onShutdown() {
15+
healthStatusManager.enterTerminalState();
16+
}
17+
18+
@Override
19+
public void setStatus(String service, HealthCheckResponse.ServingStatus status) {
20+
healthStatusManager.setStatus(service,status);
21+
}
22+
23+
@Override
24+
public void check(HealthCheckRequest request, StreamObserver<HealthCheckResponse> responseObserver) {
25+
service.check(request, responseObserver);
26+
}
27+
28+
@Override
29+
public void watch(HealthCheckRequest request, StreamObserver<HealthCheckResponse> responseObserver) {
30+
service.watch(request, responseObserver);
31+
}
32+
}
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,20 @@
33
import io.grpc.health.v1.HealthCheckResponse;
44
import io.grpc.health.v1.HealthGrpc;
55

6-
public interface GRpcHealthStatusManager {
6+
public abstract class ManagedHealthStatusService extends HealthGrpc.HealthImplBase{
77

88
/**
99
* Invoked on server shutdown. Implementation is advised to set status of all services as ServingStatus.NOT_SERVING
1010
*/
11-
void onShutdown();
11+
public abstract void onShutdown();
1212

1313
/**
1414
* Invoked on startup with {@link io.grpc.health.v1.HealthCheckResponse.ServingStatus#SERVING } for each discovered grpc service name
1515
* @param service - grpc service name
1616
* @param status - new status
1717
*/
18-
void setStatus(String service, HealthCheckResponse.ServingStatus status);
18+
public abstract void setStatus(String service, HealthCheckResponse.ServingStatus status);
1919

2020

21-
HealthGrpc.HealthImplBase getHealthService() ;
2221

2322
}

0 commit comments

Comments
 (0)