@Override
  public void shutdown(IRecordProcessorCheckpointer checkpointer, ShutdownReason reason) {
    // In cases where KCL loses lease for the shard after creating record processor instance but
    // before
    // record processor initialize() is called, then shutdown() may be called directly before
    // initialize().
    if (!initialized) {
      LOG.info(
          "Record processor was not initialized and will not have a child process, "
              + "so not invoking child process shutdown.");
      this.state = ProcessState.SHUTDOWN;
      return;
    }

    try {
      if (ProcessState.ACTIVE.equals(this.state)) {
        if (!protocol.shutdown(checkpointer, reason)) {
          throw new RuntimeException("Child process failed to shutdown");
        }

        childProcessShutdownSequence();
      } else {
        LOG.warn("Shutdown was called but this processor is already shutdown. Not doing anything.");
      }
    } catch (Throwable t) {
      if (ProcessState.ACTIVE.equals(this.state)) {
        stopProcessing("Encountered an error while trying to shutdown child process", t);
      } else {
        stopProcessing(
            "Encountered an error during shutdown,"
                + " but it appears the processor has already been shutdown",
            t);
      }
    }
  }
  @Override
  public void initialize(String shardIdToProcess) {
    try {
      this.shardId = shardIdToProcess;
      try {
        this.process = startProcess();
      } catch (IOException e) {
        /*
         * The process builder has thrown an exception while starting the child process so we would like to shut
         * down
         */
        throw new IOException("Failed to start client executable", e);
      }
      // Initialize all of our utility objects that will handle interacting with the process over
      // STDIN/STDOUT/STDERR
      messageWriter.initialize(process.getOutputStream(), shardId, objectMapper, executorService);
      messageReader.initialize(process.getInputStream(), shardId, objectMapper, executorService);
      readSTDERRTask.initialize(process.getErrorStream(), shardId, "Reading STDERR for " + shardId);

      // Submit the error reader for execution
      stderrReadTask = executorService.submit(readSTDERRTask);

      protocol = new MultiLangProtocol(messageReader, messageWriter, shardId);
      if (!protocol.initialize()) {
        throw new RuntimeException("Failed to initialize child process");
      }

      initialized = true;
    } catch (Throwable t) {
      // Any exception in initialize results in MultiLangDaemon shutdown.
      stopProcessing("Encountered an error while trying to initialize record processor", t);
    }
  }
 @Override
 public void processRecords(List<Record> records, IRecordProcessorCheckpointer checkpointer) {
   try {
     if (!protocol.processRecords(records, checkpointer)) {
       throw new RuntimeException("Child process failed to process records");
     }
   } catch (Throwable t) {
     stopProcessing("Encountered an error while trying to process records", t);
   }
 }