@Override
  public synchronized void send(final HeartbeatMessage heartbeatMessage) throws IOException {
    final long sendStart = System.nanoTime();

    final String heartbeatAddress = getHeartbeatAddress();
    final HeartbeatResponseMessage responseMessage =
        protocolSender.heartbeat(heartbeatMessage, heartbeatAddress);

    final byte[] payloadBytes = heartbeatMessage.getHeartbeat().getPayload();
    final HeartbeatPayload payload = HeartbeatPayload.unmarshal(payloadBytes);
    final List<NodeConnectionStatus> nodeStatusList = payload.getClusterStatus();
    final Map<NodeIdentifier, Long> updateIdMap =
        nodeStatusList
            .stream()
            .collect(
                Collectors.toMap(
                    status -> status.getNodeIdentifier(), status -> status.getUpdateIdentifier()));

    final List<NodeConnectionStatus> updatedStatuses = responseMessage.getUpdatedNodeStatuses();
    if (updatedStatuses != null) {
      for (final NodeConnectionStatus updatedStatus : updatedStatuses) {
        final NodeIdentifier nodeId = updatedStatus.getNodeIdentifier();
        final Long updateId = updateIdMap.get(nodeId);

        final boolean updated =
            clusterCoordinator.resetNodeStatus(updatedStatus, updateId == null ? -1L : updateId);
        if (updated) {
          logger.info(
              "After receiving heartbeat response, updated status of {} to {}",
              updatedStatus.getNodeIdentifier(),
              updatedStatus);
        } else {
          logger.debug(
              "After receiving heartbeat response, did not update status of {} to {} because the update is out-of-date",
              updatedStatus.getNodeIdentifier(),
              updatedStatus);
        }
      }
    }

    final long sendNanos = System.nanoTime() - sendStart;
    final long sendMillis = TimeUnit.NANOSECONDS.toMillis(sendNanos);

    final DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS", Locale.US);
    final String flowElectionMessage = responseMessage.getFlowElectionMessage();
    final String formattedElectionMessage =
        flowElectionMessage == null ? "" : "; " + flowElectionMessage;

    logger.info(
        "Heartbeat created at {} and sent to {} at {}; send took {} millis{}",
        dateFormatter.format(new Date(heartbeatMessage.getHeartbeat().getCreatedTimestamp())),
        heartbeatAddress,
        dateFormatter.format(new Date()),
        sendMillis,
        formattedElectionMessage);
  }