private CompletableFuture<Void> shutdownServerHandlers() {
            if (config.gracefulShutdown().timeout().isZero()) {
                return UnmodifiableFuture.completedFuture(null);
            }

            final Set<Channel> children = connectionLimitingHandler.children();
            final List<CompletableFuture<Void>> closeFutures = new ArrayList<>(children.size());
            for (Channel ch : children) {
                final HttpServerHandler serverHandler = ch.pipeline().get(HttpServerHandler.class);
                if (serverHandler != null) {
                    closeFutures.add(serverHandler.shutdown(ch));
                }
            }

            // The future returned by shutdown() will be always completed successfully.
            final CompletableFuture<List<Void>> combined = CompletableFutures.allAsList(closeFutures);
            config.workerGroup().schedule(() -> {
                combined.complete(ImmutableList.of());
                // TODO(ikhoon): Make the timeout configurable.
                // Wait for up to 1 second to send shutdown responses to clients.
            }, 1, TimeUnit.SECONDS);
            return combined.thenApply(ignored -> null);
        }
Closes all channels and terminates all event loops.
<ol>
  <li>Closes all server channels so that we don't accept any more incoming connections.</li>
  <li>Closes all accepted channels.</li>
  <li>Shuts down the worker group if necessary.</li>
  <li>Shuts down the boss groups.</li>
</ol>
Note that we terminate the boss groups lastly so that the JVM does not terminate itself
even if other threads are daemon, because boss group threads are always non-daemon.
core/src/main/java/com/linecorp/armeria/server/Server.java