docs: protected CompletableFuture<Void> shutDownInternal() {
  
  		synchronized (lock) {
  
  			CompletableFuture<?> channelFuture = new CompletableFuture<>();
  			if (serverChannel != null) {
  				serverChannel.close().addListener(finished -> {
  					if (finished.isSuccess()) {
  						channelFuture.complete(null);
  					} else {
  						channelFuture.completeExceptionally(finished.cause());
  					}
  				});
  				serverChannel = null;
  			}
  
  			final CompletableFuture<Void> channelTerminationFuture = new CompletableFuture<>();
  
  			channelFuture.thenRun(() -> {
  				CompletableFuture<?> groupFuture = new CompletableFuture<>();
  				CompletableFuture<?> childGroupFuture = new CompletableFuture<>();
  				final Time gracePeriod = Time.seconds(10L);
  
  				if (bootstrap != null) {
  					final ServerBootstrapConfig config = bootstrap.config();
  					final EventLoopGroup group = config.group();
  					if (group != null) {
  						group.shutdownGracefully(0L, gracePeriod.toMilliseconds(), TimeUnit.MILLISECONDS)
  							.addListener(finished -> {
  								if (finished.isSuccess()) {
  									groupFuture.complete(null);
  								} else {
  									groupFuture.completeExceptionally(finished.cause());
  								}
  							});
  					} else {
  						groupFuture.complete(null);
  					}
  
  					final EventLoopGroup childGroup = config.childGroup();
  					if (childGroup != null) {
  						childGroup.shutdownGracefully(0L, gracePeriod.toMilliseconds(), TimeUnit.MILLISECONDS)
  							.addListener(finished -> {
  								if (finished.isSuccess()) {
  									childGroupFuture.complete(null);
  								} else {
  									childGroupFuture.completeExceptionally(finished.cause());
  								}
  							});
  					} else {
  						childGroupFuture.complete(null);
  					}
  
  					bootstrap = null;
  				} else {
  					// complete the group futures since there is nothing to stop
  					groupFuture.complete(null);
  					childGroupFuture.complete(null);
  				}
  
  				CompletableFuture<Void> combinedFuture = FutureUtils.completeAll(Arrays.asList(groupFuture, childGroupFuture));
  
  				combinedFuture.whenComplete(
  					(Void ignored, Throwable throwable) -> {
  						if (throwable != null) {
  							channelTerminationFuture.completeExceptionally(throwable);
  						} else {
  							channelTerminationFuture.complete(null);
  						}
  					});
  			});
  
  			return channelTerminationFuture;
  		}
  	}