Skip to content

Commit d39b809

Browse files
committed
Wait for the grpc-server to gracefully shutdown
Otherwise the spring context might already be shutdown and the calls fail, because other components are already shutdown.
1 parent 74e0f1c commit d39b809

File tree

4 files changed

+73
-25
lines changed

4 files changed

+73
-25
lines changed

grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/autoconfigure/GrpcServerAutoConfiguration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ public List<GrpcServerConfigurer> defaultServerConfigurers() {
135135
@ConditionalOnMissingBean
136136
@ConditionalOnBean(GrpcServerFactory.class)
137137
@Bean
138-
public GrpcServerLifecycle grpcServerLifecycle(final GrpcServerFactory factory) {
139-
return new GrpcServerLifecycle(factory);
138+
public GrpcServerLifecycle grpcServerLifecycle(final GrpcServerFactory factory, GrpcServerProperties properties) {
139+
return new GrpcServerLifecycle(factory, properties.getGracefullShutdownTimeout());
140140
}
141141

142142
}

grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/autoconfigure/GrpcServerFactoryAutoConfiguration.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,16 @@ public ShadedNettyGrpcServerFactory shadedNettyGrpcServerFactory(
8282
* The server lifecycle bean for a shaded netty based server.
8383
*
8484
* @param factory The factory used to create the lifecycle.
85+
* @param properties The server properties to use.
8586
* @return The inter-process server lifecycle bean.
8687
*/
8788
@ConditionalOnBean(ShadedNettyGrpcServerFactory.class)
8889
@Bean
89-
public GrpcServerLifecycle shadedNettyGrpcServerLifecycle(final ShadedNettyGrpcServerFactory factory) {
90-
return new GrpcServerLifecycle(factory);
90+
public GrpcServerLifecycle shadedNettyGrpcServerLifecycle(
91+
final ShadedNettyGrpcServerFactory factory,
92+
final GrpcServerProperties properties) {
93+
94+
return new GrpcServerLifecycle(factory, properties.getGracefullShutdownTimeout());
9195
}
9296

9397
// Then try the normal netty server
@@ -120,12 +124,16 @@ public NettyGrpcServerFactory nettyGrpcServerFactory(
120124
* The server lifecycle bean for netty based server.
121125
*
122126
* @param factory The factory used to create the lifecycle.
127+
* @param properties The server properties to use.
123128
* @return The inter-process server lifecycle bean.
124129
*/
125130
@ConditionalOnBean(NettyGrpcServerFactory.class)
126131
@Bean
127-
public GrpcServerLifecycle nettyGrpcServerLifecycle(final NettyGrpcServerFactory factory) {
128-
return new GrpcServerLifecycle(factory);
132+
public GrpcServerLifecycle nettyGrpcServerLifecycle(
133+
final NettyGrpcServerFactory factory,
134+
final GrpcServerProperties properties) {
135+
136+
return new GrpcServerLifecycle(factory, properties.getGracefullShutdownTimeout());
129137
}
130138

131139
/**
@@ -153,12 +161,16 @@ public InProcessGrpcServerFactory inProcessGrpcServerFactory(
153161
* The server lifecycle bean for the in-process-server.
154162
*
155163
* @param factory The factory used to create the lifecycle.
164+
* @param properties The server properties to use.
156165
* @return The in-process server lifecycle bean.
157166
*/
158167
@ConditionalOnBean(InProcessGrpcServerFactory.class)
159168
@Bean
160-
public GrpcServerLifecycle inProcessGrpcServerLifecycle(final InProcessGrpcServerFactory factory) {
161-
return new GrpcServerLifecycle(factory);
169+
public GrpcServerLifecycle inProcessGrpcServerLifecycle(
170+
final InProcessGrpcServerFactory factory,
171+
final GrpcServerProperties properties) {
172+
173+
return new GrpcServerLifecycle(factory, properties.getGracefullShutdownTimeout());
162174
}
163175

164176
}

grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/config/GrpcServerProperties.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ public class GrpcServerProperties {
9393
*/
9494
private String inProcessName;
9595

96+
/**
97+
* The time to wait for the server to gracefully shutdown (completing all requests after the server started to
98+
* shutdown). If set to {@code -1} the server waits forever. If set to {@code 0} the server will force shutdown
99+
* immediately. Defaults to {@code 30s}.
100+
*
101+
* @param gracefullShutdownTimeout The time to wait for a graceful shutdown.
102+
* @return The time to wait for a graceful shutdown.
103+
*/
104+
@DurationUnit(ChronoUnit.SECONDS)
105+
private Duration gracefullShutdownTimeout = Duration.of(30, ChronoUnit.SECONDS);
106+
96107
/**
97108
* Setting to enable keepAlive. Default to {@code false}.
98109
*

grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/serverfactory/GrpcServerLifecycle.java

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717

1818
package net.devh.boot.grpc.server.serverfactory;
1919

20+
import static java.util.Objects.requireNonNull;
21+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
22+
2023
import java.io.IOException;
24+
import java.time.Duration;
2125
import java.util.concurrent.atomic.AtomicInteger;
2226

2327
import org.springframework.context.SmartLifecycle;
@@ -29,18 +33,26 @@
2933
* Lifecycle bean that automatically starts and stops the grpc server.
3034
*
3135
* @author Michael ([email protected])
32-
* @since 5/17/16
3336
*/
3437
@Slf4j
3538
public class GrpcServerLifecycle implements SmartLifecycle {
39+
3640
private static AtomicInteger serverCounter = new AtomicInteger(-1);
3741

38-
private volatile Server server;
39-
private volatile int phase = Integer.MAX_VALUE;
4042
private final GrpcServerFactory factory;
43+
private final Duration gracefulShutdownTimeout;
4144

42-
public GrpcServerLifecycle(final GrpcServerFactory factory) {
43-
this.factory = factory;
45+
private Server server;
46+
47+
/**
48+
* Creates a new GrpcServerLifecycle
49+
*
50+
* @param factory The server factory to use.
51+
* @param gracefulShutdownTimeout The time to wait for the server to gracefully shut down.
52+
*/
53+
public GrpcServerLifecycle(final GrpcServerFactory factory, final Duration gracefulShutdownTimeout) {
54+
this.factory = requireNonNull(factory, "factory");
55+
this.gracefulShutdownTimeout = requireNonNull(gracefulShutdownTimeout, "gracefulShutdownTimeout");
4456
}
4557

4658
@Override
@@ -70,7 +82,7 @@ public boolean isRunning() {
7082

7183
@Override
7284
public int getPhase() {
73-
return this.phase;
85+
return Integer.MAX_VALUE;
7486
}
7587

7688
@Override
@@ -84,41 +96,54 @@ public boolean isAutoStartup() {
8496
* @throws IOException If the server is unable to bind the port.
8597
*/
8698
protected void createAndStartGrpcServer() throws IOException {
87-
final Server localServer = this.server;
88-
if (localServer == null) {
89-
this.server = this.factory.createServer();
90-
this.server.start();
99+
if (this.server == null) {
100+
final Server localServer = this.factory.createServer();
101+
this.server = localServer;
102+
localServer.start();
91103
log.info("gRPC Server started, listening on address: " + this.factory.getAddress() + ", port: "
92104
+ this.factory.getPort());
93105

94106
// Prevent the JVM from shutting down while the server is running
95107
final Thread awaitThread = new Thread(() -> {
96108
try {
97-
this.server.awaitTermination();
109+
localServer.awaitTermination();
98110
} catch (final InterruptedException e) {
99111
Thread.currentThread().interrupt();
100112
}
101-
}, "grpc-server-container-" + (serverCounter.incrementAndGet()));
113+
});
114+
awaitThread.setName("grpc-server-container-" + (serverCounter.incrementAndGet()));
102115
awaitThread.setDaemon(false);
103116
awaitThread.start();
104117
}
105118
}
106119

107120
/**
108-
* Initiates an orderly shutdown of the grpc server and releases the references to the server. This call does not
109-
* wait for the server to be completely shut down.
121+
* Initiates an orderly shutdown of the grpc server and releases the references to the server. This call waits for
122+
* the server to be completely shut down.
110123
*/
111124
protected void stopAndReleaseGrpcServer() {
112125
final Server localServer = this.server;
113126
if (localServer != null) {
127+
final long millis = this.gracefulShutdownTimeout.toMillis();
128+
log.debug("Initiating gRPC server shutdown");
114129
localServer.shutdown();
130+
// Wait for the server to shutdown completely before continuing with destroying the spring context
115131
try {
116-
this.server.awaitTermination();
132+
if (millis > 0) {
133+
localServer.awaitTermination(millis, MILLISECONDS);
134+
} else if (millis == 0) {
135+
// Do not wait
136+
} else {
137+
// Wait infinitely
138+
localServer.awaitTermination();
139+
}
117140
} catch (final InterruptedException e) {
118141
Thread.currentThread().interrupt();
142+
} finally {
143+
localServer.shutdownNow();
144+
this.server = null;
119145
}
120-
this.server = null;
121-
log.info("gRPC server shutdown.");
146+
log.info("Completed gRPC server shutdown");
122147
}
123148
}
124149

0 commit comments

Comments
 (0)