code: void exit(int exitCode) {
      if (isExited) {
        return;
      }
      // First, stop reading from the socket. If we won't do that then client receives an exit code
      // and terminates
      // the socket on its end, causing readExecutor to throw
      try {
        stopIn();
      } catch (IOException ex) {
        LOG.log(
            Level.WARNING, "Unable to close socket for reading while sending final exit code", ex);
      }
  
      // send the command - client will exit
      try (PrintStream exit = new PrintStream(new NGOutputStream(this, NGConstants.CHUNKTYPE_EXIT))) {
        exit.println(exitCode);
      }
      isExited = true;
  
      // close writing too - there is no point to send anything to client after the resulting exit
      // code
      try {
        stopOut();
      } catch (IOException ex) {
        LOG.log(
            Level.WARNING, "Unable to close socket for writing while sending final exit code", ex);
      }
    }
docs: Signal nail completion to the client. It will close communication socket afterwards, so any
  read or write would result in an error This method is idempotent and need to be called only
  once. Any subsequent call will result in noop.
  
  @param exitCode exit code as output by Nailgun client