Skip to content

Commit 6177014

Browse files
committed
#5737 - Nima: Add WebServer.Builder configuration option to support not registering JVM shutdown hook
- Add WebServer.Builder.shutdownHook(false) configuration option - Add support for de-registering the shutdown hook when the webserver is explicitly stopped - Modify HelidonServerJunitExtension to use shutdownHook(false)
1 parent 6244d82 commit 6177014

File tree

4 files changed

+45
-7
lines changed

4 files changed

+45
-7
lines changed

lra/coordinator/server/src/test/java/io/helidon/lra/coordinator/CoordinatorTest.java

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ static void beforeAll() {
6363
.build().get(CoordinatorService.CONFIG_PREFIX))
6464
.build();
6565
server = WebServer.builder()
66+
.shutdownHook(true)
6667
.host("localhost")
6768
.routing(r -> r.register(CONTEXT_PATH, () -> rules -> rules.put((req, res) -> res.send())))
6869
.socket(COORDINATOR_ROUTING_NAME, (socket, routing) -> {

nima/testing/junit5/webserver/src/main/java/io/helidon/nima/testing/junit5/webserver/HelidonServerJunitExtension.java

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public void beforeAll(ExtensionContext context) {
7676

7777
WebServer.Builder builder = WebServer.builder()
7878
.port(0)
79+
.shutdownHook(false)
7980
.host("localhost");
8081

8182
setupServer(builder);

nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/LoomServer.java

+25-7
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,14 @@ class LoomServer implements WebServer {
4444
private final AtomicBoolean running = new AtomicBoolean();
4545
private final Lock lifecycleLock = new ReentrantLock();
4646
private final ExecutorService executorService;
47+
private final boolean registerShutdownHook;
48+
private volatile Thread shutdownHook;
4749

4850
private volatile List<ListenerFuture> startFutures;
4951
private volatile boolean alreadyStarted = false;
5052

5153
LoomServer(Builder builder, DirectHandlers simpleHandlers) {
54+
this.registerShutdownHook = builder.shutdownHook();
5255
ServerContextImpl serverContext = new ServerContextImpl(builder.context(),
5356
builder.mediaContext(),
5457
builder.contentEncodingContext());
@@ -162,6 +165,7 @@ private void stopIt() {
162165
running.set(false);
163166

164167
LOGGER.log(System.Logger.Level.INFO, "Níma server stopped all channels.");
168+
deregisterShutdownHook();
165169
}
166170

167171
private void startIt() {
@@ -175,13 +179,9 @@ private void startIt() {
175179
}
176180
return;
177181
}
178-
Runtime.getRuntime()
179-
.addShutdownHook(new Thread(() -> {
180-
listeners.values().forEach(ServerListener::stop);
181-
if (startFutures != null) {
182-
startFutures.forEach(future -> future.future().cancel(true));
183-
}
184-
}, "shutdown-hook"));
182+
if (registerShutdownHook) {
183+
registerShutdownHook();
184+
}
185185
now = System.currentTimeMillis() - now;
186186
long uptime = ManagementFactory.getRuntimeMXBean().getUptime();
187187

@@ -197,6 +197,24 @@ private void startIt() {
197197
}
198198
}
199199

200+
private void registerShutdownHook() {
201+
this.shutdownHook = new Thread(() -> {
202+
listeners.values().forEach(ServerListener::stop);
203+
if (startFutures != null) {
204+
startFutures.forEach(future -> future.future().cancel(true));
205+
}
206+
}, "shutdown-hook");
207+
208+
Runtime.getRuntime().addShutdownHook(shutdownHook);
209+
}
210+
211+
private void deregisterShutdownHook() {
212+
if (shutdownHook != null) {
213+
Runtime.getRuntime().removeShutdownHook(shutdownHook);
214+
shutdownHook = null;
215+
}
216+
}
217+
200218
// return false if anything fails
201219
private boolean parallel(String taskName, Consumer<ServerListener> task) {
202220
boolean result = true;

nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/WebServer.java

+18
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class Builder implements io.helidon.common.Builder<Builder, WebServer>, Router.R
143143
private MediaContext mediaContext = MediaContext.create();
144144
private ContentEncodingContext contentEncodingContext = ContentEncodingContext.create();
145145

146+
private boolean shutdownHook = true;
146147
private Context context;
147148

148149
Builder(Config rootConfig) {
@@ -407,10 +408,27 @@ public Builder context(Context context) {
407408
return this;
408409
}
409410

411+
/**
412+
* When true the webserver registers a shutdown hook with the JVM Runtime.
413+
* <p>
414+
* Defaults to true. Set this to false such that a shutdown hook is not registered.
415+
*
416+
* @param shutdownHook When true register a shutdown hook
417+
* @return updated builder
418+
*/
419+
public Builder shutdownHook(boolean shutdownHook) {
420+
this.shutdownHook = shutdownHook;
421+
return this;
422+
}
423+
410424
Context context() {
411425
return context;
412426
}
413427

428+
boolean shutdownHook() {
429+
return shutdownHook;
430+
}
431+
414432
MediaContext mediaContext() {
415433
return this.mediaContext;
416434
}

0 commit comments

Comments
 (0)