Skip to content

Commit 3a96620

Browse files
feat: add server shutdown util (#20)
1 parent 6f773e9 commit 3a96620

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

grpc-server-utils/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,9 @@ dependencies {
2424
}
2525
}
2626

27+
annotationProcessor("org.projectlombok:lombok:1.18.20")
28+
compileOnly("org.projectlombok:lombok:1.18.20")
29+
2730
testImplementation("org.junit.jupiter:junit-jupiter:5.7.0")
31+
testImplementation("org.mockito:mockito-core:3.12.1")
2832
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.hypertrace.core.grpcutils.server;
2+
3+
import io.grpc.Server;
4+
import java.time.Duration;
5+
import java.util.concurrent.TimeUnit;
6+
import lombok.extern.slf4j.Slf4j;
7+
8+
@Slf4j
9+
public class ServerManagementUtil {
10+
11+
public static void shutdownServer(Server grpcServer, String name, Duration timeout) {
12+
log.info("Starting shutdown for service [{}]", name);
13+
grpcServer.shutdown();
14+
boolean gracefullyShutdown = waitForGracefulShutdown(grpcServer, name, timeout);
15+
if (!gracefullyShutdown) {
16+
forceShutdown(grpcServer, name);
17+
}
18+
}
19+
20+
private static boolean waitForGracefulShutdown(Server grpcServer, String name, Duration timeout) {
21+
boolean successfullyShutdown = waitForTermination(grpcServer, name, timeout);
22+
if (successfullyShutdown) {
23+
log.info("Shutdown service successfully [{}]", name);
24+
}
25+
return successfullyShutdown;
26+
}
27+
28+
private static void forceShutdown(Server grpcServer, String name) {
29+
log.error("Shutting down service [{}] forcefully", name);
30+
grpcServer.shutdownNow();
31+
if (waitForTermination(grpcServer, name, Duration.ofSeconds(5))) {
32+
log.error("Forced service [{}] shutdown successful", name);
33+
} else {
34+
log.error("Unable to force service [{}] shutdown in 5s - giving up!", name);
35+
}
36+
}
37+
38+
private static boolean waitForTermination(Server grpcServer, String name, Duration deadline) {
39+
try {
40+
if (!grpcServer.awaitTermination(deadline.toMillis(), TimeUnit.MILLISECONDS)) {
41+
log.error("Service [{}] did not shut down after waiting", name);
42+
}
43+
} catch (InterruptedException ex) {
44+
log.error("There has been an interruption while waiting for service [{}] to shutdown", name);
45+
Thread.currentThread().interrupt();
46+
}
47+
return grpcServer.isTerminated();
48+
}
49+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.hypertrace.core.grpcutils.server;
2+
3+
import static org.mockito.Mockito.inOrder;
4+
import static org.mockito.Mockito.mock;
5+
import static org.mockito.Mockito.when;
6+
7+
import io.grpc.Server;
8+
import java.time.Duration;
9+
import java.time.temporal.ChronoUnit;
10+
import java.util.concurrent.TimeUnit;
11+
import org.junit.jupiter.api.Test;
12+
import org.mockito.InOrder;
13+
14+
class ServerManagementUtilTest {
15+
16+
@Test
17+
void canShutdownGracefully() throws InterruptedException {
18+
Server mockServer = mock(Server.class);
19+
when(mockServer.isTerminated()).thenReturn(true);
20+
ServerManagementUtil.shutdownServer(
21+
mockServer, "mockServer", Duration.of(10, ChronoUnit.MILLIS));
22+
23+
InOrder serverVerifier = inOrder(mockServer);
24+
serverVerifier.verify(mockServer).shutdown();
25+
serverVerifier.verify(mockServer).awaitTermination(10, TimeUnit.MILLISECONDS);
26+
serverVerifier.verify(mockServer).isTerminated();
27+
serverVerifier.verifyNoMoreInteractions();
28+
}
29+
30+
@Test
31+
void canShutdownForcefully() throws InterruptedException {
32+
Server mockServer = mock(Server.class);
33+
when(mockServer.isTerminated()).thenReturn(false);
34+
ServerManagementUtil.shutdownServer(
35+
mockServer, "mockServer", Duration.of(10, ChronoUnit.MILLIS));
36+
37+
InOrder serverVerifier = inOrder(mockServer);
38+
serverVerifier.verify(mockServer).shutdown();
39+
serverVerifier.verify(mockServer).awaitTermination(10, TimeUnit.MILLISECONDS);
40+
serverVerifier.verify(mockServer).isTerminated();
41+
serverVerifier.verify(mockServer).shutdownNow();
42+
serverVerifier.verify(mockServer).awaitTermination(5000, TimeUnit.MILLISECONDS);
43+
serverVerifier.verify(mockServer).isTerminated();
44+
serverVerifier.verifyNoMoreInteractions();
45+
}
46+
}

0 commit comments

Comments
 (0)