/**
   * 发送JobResults
   *
   * @param results
   * @return
   */
  private boolean retrySendJobResults(List<TaskTrackerJobResult> results) {
    // 发送消息给 JobTracker
    TtJobFinishedRequest requestBody =
        application.getCommandBodyWrapper().wrapper(new TtJobFinishedRequest());
    requestBody.setTaskTrackerJobResults(results);
    requestBody.setReSend(true);

    int requestCode = JobProtos.RequestCode.JOB_FINISHED.code();
    RemotingCommand request = RemotingCommand.createRequestCommand(requestCode, requestBody);

    try {
      // 这里一定要用同步,不然异步会发生文件锁,死锁
      RemotingCommand commandResponse = remotingClient.invokeSync(request);
      if (commandResponse != null
          && commandResponse.getCode() == RemotingProtos.ResponseCode.SUCCESS.code()) {
        return true;
      } else {
        LOGGER.warn("Send job failed, {}", commandResponse);
        return false;
      }
    } catch (JobTrackerNotFoundException e) {
      LOGGER.error("Retry send job result failed! jobResults={}", results, e);
    }
    return false;
  }
    @Override
    public JobWrapper runComplete(Response response) {
      // 发送消息给 JobTracker
      final TaskTrackerJobResult taskTrackerJobResult = new TaskTrackerJobResult();
      taskTrackerJobResult.setTime(SystemClock.now());
      taskTrackerJobResult.setJobWrapper(response.getJobWrapper());
      taskTrackerJobResult.setAction(response.getAction());
      taskTrackerJobResult.setMsg(response.getMsg());
      TtJobFinishedRequest requestBody =
          application.getCommandBodyWrapper().wrapper(new TtJobFinishedRequest());
      requestBody.addJobResult(taskTrackerJobResult);
      requestBody.setReceiveNewJob(response.isReceiveNewJob()); // 设置可以接受新任务

      int requestCode = JobProtos.RequestCode.JOB_FINISHED.code();

      RemotingCommand request = RemotingCommand.createRequestCommand(requestCode, requestBody);

      final Response returnResponse = new Response();

      try {
        final CountDownLatch latch = new CountDownLatch(1);
        remotingClient.invokeAsync(
            request,
            new InvokeCallback() {
              @Override
              public void operationComplete(ResponseFuture responseFuture) {
                try {
                  RemotingCommand commandResponse = responseFuture.getResponseCommand();

                  if (commandResponse != null
                      && commandResponse.getCode() == RemotingProtos.ResponseCode.SUCCESS.code()) {
                    JobPushRequest jobPushRequest = commandResponse.getBody();
                    if (jobPushRequest != null) {
                      LOGGER.info("Get new job :{}", jobPushRequest.getJobWrapper());
                      returnResponse.setJobWrapper(jobPushRequest.getJobWrapper());
                    }
                  } else {
                    LOGGER.info("Job feedback failed, save local files。{}", taskTrackerJobResult);
                    try {
                      retryScheduler.inSchedule(
                          taskTrackerJobResult.getJobWrapper().getJobId().concat("_")
                              + SystemClock.now(),
                          taskTrackerJobResult);
                    } catch (Exception e) {
                      LOGGER.error("Job feedback failed", e);
                    }
                  }
                } finally {
                  latch.countDown();
                }
              }
            });

        try {
          latch.await(Constants.LATCH_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
          throw new RequestTimeoutException(e);
        }
      } catch (JobTrackerNotFoundException e) {
        try {
          LOGGER.warn("No job tracker available! save local files.");
          retryScheduler.inSchedule(
              taskTrackerJobResult.getJobWrapper().getJobId().concat("_") + SystemClock.now(),
              taskTrackerJobResult);
        } catch (Exception e1) {
          LOGGER.error("Save files failed, {}", taskTrackerJobResult.getJobWrapper(), e1);
        }
      }

      return returnResponse.getJobWrapper();
    }