in gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/GremlinServer.java [231:352]
public synchronized CompletableFuture<Void> stop() {
if (serverStopped != null) {
// shutdown has started so don't fire it off again
return serverStopped;
}
serverStopped = new CompletableFuture<>();
final CountDownLatch servicesLeftToShutdown = new CountDownLatch(3);
// it's possible that a channel might not be initialized in the first place if bind() fails because
// of port conflict. in that case, there's no need to wait for the channel to close.
if (null == serverSocketChannel)
servicesLeftToShutdown.countDown();
else
serverSocketChannel.close().addListener(f -> servicesLeftToShutdown.countDown());
logger.info("Shutting down thread pools.");
try {
if (gremlinExecutorService != null) gremlinExecutorService.shutdown();
} finally {
logger.debug("Shutdown Gremlin thread pool.");
}
try {
workerGroup.shutdownGracefully().addListener((GenericFutureListener) f -> servicesLeftToShutdown.countDown());
} finally {
logger.debug("Shutdown Worker thread pool.");
}
try {
bossGroup.shutdownGracefully().addListener((GenericFutureListener) f -> servicesLeftToShutdown.countDown());
} finally {
logger.debug("Shutdown Boss thread pool.");
}
// channel is shutdown as are the thread pools - time to kill graphs as nothing else should be acting on them
new Thread(() -> {
if (serverGremlinExecutor != null) {
serverGremlinExecutor.getHooks().forEach(hook -> {
logger.info("Executing shutdown {}", LifeCycleHook.class.getSimpleName());
try {
hook.onShutDown(new LifeCycleHook.Context(logger));
} catch (UnsupportedOperationException | UndeclaredThrowableException uoe) {
// if the user doesn't implement onShutDown the scriptengine will throw
// this exception. it can safely be ignored.
}
});
}
try {
if (gremlinExecutorService != null) {
if (!gremlinExecutorService.awaitTermination(30000, TimeUnit.MILLISECONDS)) {
logger.warn("Gremlin thread pool did not fully terminate - continuing with shutdown process");
}
}
} catch (InterruptedException ie) {
logger.warn("Timeout waiting for Gremlin thread pool to shutdown - continuing with shutdown process.");
}
try {
servicesLeftToShutdown.await(30000, TimeUnit.MILLISECONDS);
} catch (InterruptedException ie) {
logger.warn("Timeout waiting for boss/worker thread pools to shutdown - continuing with shutdown process.");
}
// close TraversalSource and Graph instances - there aren't guarantees that closing Graph will close all
// spawned TraversalSource instances so both should be closed directly and independently.
if (serverGremlinExecutor != null) {
final Set<String> traversalSourceNames = serverGremlinExecutor.getGraphManager().getTraversalSourceNames();
traversalSourceNames.forEach(traversalSourceName -> {
logger.debug("Closing GraphTraversalSource instance [{}]", traversalSourceName);
try {
serverGremlinExecutor.getGraphManager().getTraversalSource(traversalSourceName).close();
} catch (Exception ex) {
logger.warn(String.format("Exception while closing GraphTraversalSource instance [%s]", traversalSourceName), ex);
} finally {
logger.info("Closed GraphTraversalSource instance [{}]", traversalSourceName);
}
try {
serverGremlinExecutor.getGraphManager().removeTraversalSource(traversalSourceName);
} catch (Exception ex) {
logger.warn(String.format("Exception while removing GraphTraversalSource instance [%s] from GraphManager", traversalSourceName), ex);
}
});
final Set<String> graphNames = serverGremlinExecutor.getGraphManager().getGraphNames();
graphNames.forEach(gName -> {
logger.debug("Closing Graph instance [{}]", gName);
try {
final Graph graph = serverGremlinExecutor.getGraphManager().getGraph(gName);
graph.close();
} catch (Exception ex) {
logger.warn(String.format("Exception while closing Graph instance [%s]", gName), ex);
} finally {
logger.info("Closed Graph instance [{}]", gName);
}
try {
serverGremlinExecutor.getGraphManager().removeGraph(gName);
} catch (Exception ex) {
logger.warn(String.format("Exception while removing Graph instance [%s] from GraphManager", gName), ex);
}
});
}
// kills reporter threads. this is a last bit of cleanup that can be done. typically, the jvm is headed
// for shutdown which would obviously kill the reporters, but when it isn't they just keep reporting.
// removing them all will silent them up and release the appropriate resources.
MetricManager.INSTANCE.removeAllReporters();
// removing all the metrics should allow Gremlin Server to clean up the metrics instance so that it can be
// started again in the same JVM without those metrics initialized which generates a warning and won't
// reset to start values
MetricManager.INSTANCE.removeAllMetrics();
logger.info("Gremlin Server - shutdown complete");
serverStopped.complete(null);
}, SERVER_THREAD_PREFIX + "stop").start();
return serverStopped;
}