@Override
    protected Void callInternal() {
      LOG.trace("Attempting to heartbeat to AM: {}", amNodeInfo);
      TaskSnapshot tasks = amNodeInfo.getTasksSnapshot();
      if (tasks.attempts.isEmpty()) {
        return null;
      }
      try {
        LOG.trace("NodeHeartbeat to: {}", amNodeInfo);
        // TODO: if there are more fields perhaps there should be an array of class.
        TezAttemptArray aw = new TezAttemptArray();
        aw.set(tasks.attempts.toArray(new TezTaskAttemptID[tasks.attempts.size()]));
        BooleanArray guaranteed = new BooleanArray();
        guaranteed.set(tasks.guaranteed.toArray(new BooleanWritable[tasks.guaranteed.size()]));

        if (LlapUtil.isCloudDeployment(conf) && amNodeInfo.isExternalClientRequest()) {
          String hostname = amNodeInfo.amNodeId.getHostname();
          int externalClientCloudRpcPort = amNodeInfo.amNodeId.getPort();
          amNodeInfo.getUmbilical().nodeHeartbeat(new Text(hostname),
                  new Text(daemonId.getUniqueNodeIdInCluster()), externalClientCloudRpcPort, aw, guaranteed);
        } else {
          amNodeInfo.getUmbilical().nodeHeartbeat(new Text(nodeId.getHostname()),
                  new Text(daemonId.getUniqueNodeIdInCluster()), nodeId.getPort(), aw, guaranteed);
        }
      } catch (IOException e) {
        QueryIdentifier currentQueryIdentifier = amNodeInfo.getQueryIdentifier();
        amNodeInfo.setAmFailed(true);
        LOG.warn("Failed to communicated with AM at {}. Killing remaining fragments for query {}",
            amNodeInfo.amNodeId, currentQueryIdentifier, e);
        queryFailedHandler.queryFailed(currentQueryIdentifier);
      } catch (InterruptedException e) {
        if (!isShutdown.get()) {
          LOG.warn("Interrupted while trying to send heartbeat to AM {}", amNodeInfo.amNodeId, e);
        }
      }

      return null;
    }
Responsible for communicating with various AMs.
llap-server/src/java/org/apache/hadoop/hive/llap/daemon/impl/AMReporter.java