@Override
  public boolean process(Message<? extends MessageType> message) {
    if (!message.isInternal() && !message.getMessageType().equals(HeartbeatMessage.i_am_alive)) {
      // We assume the FROM header always exists.
      String from = message.getHeader(Message.FROM);
      if (!from.equals(message.getHeader(Message.TO))) {
        InstanceId theId;
        if (message.hasHeader(Message.INSTANCE_ID)) {
          // INSTANCE_ID is there since after 1.9.6
          theId = new InstanceId(Integer.parseInt(message.getHeader(Message.INSTANCE_ID)));
        } else {
          theId = clusterContext.getConfiguration().getIdForUri(URI.create(from));
        }

        if (theId != null
            && clusterContext.getConfiguration().getMembers().containsKey(theId)
            && !clusterContext.isMe(theId)) {
          output.offer(
              message.copyHeadersTo(
                  Message.internal(
                      HeartbeatMessage.i_am_alive, new HeartbeatMessage.IAmAliveState(theId)),
                  Message.FROM,
                  Message.INSTANCE_ID));
        }
      }
    }
    return true;
  }
Example #2
0
    @Override
    public HeartbeatState handle(
        HeartbeatContext context, Message<HeartbeatMessage> message, MessageHolder outgoing)
        throws Throwable {
      switch (message.getMessageType()) {
        case i_am_alive:
          {
            HeartbeatMessage.IAmAliveState state = message.getPayload();

            if (context.getClusterContext().isMe(state.getServer())) {
              break;
            }

            context.getClusterContext().getLogger(HeartbeatState.class).debug("Received " + state);

            if (state.getServer() == null) {
              break;
            }

            if (context.alive(state.getServer())) {
              // Send suspicions messages to all non-failed servers
              for (InstanceId aliveServer : context.getAlive()) {
                if (!aliveServer.equals(context.getClusterContext().getMyId())) {
                  URI aliveServerUri =
                      context.getClusterContext().configuration.getUriForId(aliveServer);
                  outgoing.offer(
                      Message.to(
                          HeartbeatMessage.suspicions,
                          aliveServerUri,
                          new HeartbeatMessage.SuspicionsState(
                              context.getSuspicionsFor(context.getClusterContext().getMyId()))));
                }
              }
            }

            context
                .getClusterContext()
                .timeouts
                .cancelTimeout(HeartbeatMessage.i_am_alive + "-" + state.getServer());
            context
                .getClusterContext()
                .timeouts
                .setTimeout(
                    HeartbeatMessage.i_am_alive + "-" + state.getServer(),
                    timeout(HeartbeatMessage.timed_out, message, state.getServer()));

            // Check if this server knows something that we don't
            if (message.hasHeader("last-learned")) {
              long lastLearned = Long.parseLong(message.getHeader("last-learned"));
              if (lastLearned
                  > context.getLearnerContext().getLastKnownLearnedInstanceInCluster()) {
                outgoing.offer(internal(LearnerMessage.catchUp, lastLearned));
              }
            }

            break;
          }

        case timed_out:
          {
            InstanceId server = message.getPayload();
            context
                .getClusterContext()
                .getLogger(HeartbeatState.class)
                .debug("Received timed out for server " + server);
            // Check if this node is no longer a part of the cluster
            if (context.getClusterContext().getConfiguration().getMembers().containsKey(server)) {
              context.suspect(server);

              context
                  .getClusterContext()
                  .timeouts
                  .setTimeout(
                      HeartbeatMessage.i_am_alive + "-" + server,
                      timeout(HeartbeatMessage.timed_out, message, server));

              // Send suspicions messages to all non-failed servers
              for (InstanceId aliveServer : context.getAlive()) {
                if (!aliveServer.equals(context.getClusterContext().getMyId())) {
                  URI sendTo =
                      context.getClusterContext().getConfiguration().getUriForId(aliveServer);
                  outgoing.offer(
                      Message.to(
                          HeartbeatMessage.suspicions,
                          sendTo,
                          new HeartbeatMessage.SuspicionsState(
                              context.getSuspicionsFor(context.getClusterContext().getMyId()))));
                }
              }
            } else {
              // If no longer part of cluster, then don't bother
              context.serverLeftCluster(server);
            }
            break;
          }

        case sendHeartbeat:
          {
            InstanceId to = message.getPayload();

            // Check if this node is no longer a part of the cluster
            if (!context.getClusterContext().isMe(to)
                && context.getClusterContext().getConfiguration().getMembers().containsKey(to)) {
              URI toSendTo = context.getClusterContext().getConfiguration().getUriForId(to);
              // Send heartbeat message to given server
              outgoing.offer(
                  to(
                          HeartbeatMessage.i_am_alive,
                          toSendTo,
                          new HeartbeatMessage.IAmAliveState(context.getClusterContext().getMyId()))
                      .setHeader(
                          "last-learned",
                          context.getLearnerContext().getLastLearnedInstanceId() + ""));

              // Set new timeout to send heartbeat to this host
              context
                  .getClusterContext()
                  .timeouts
                  .setTimeout(
                      HeartbeatMessage.sendHeartbeat + "-" + to,
                      timeout(HeartbeatMessage.sendHeartbeat, message, to));
            }
            break;
          }

        case reset_send_heartbeat:
          {
            InstanceId to = message.getPayload();

            if (!context.getClusterContext().isMe(to)) {
              String timeoutName = HeartbeatMessage.sendHeartbeat + "-" + to;
              context.getClusterContext().timeouts.cancelTimeout(timeoutName);
              context
                  .getClusterContext()
                  .timeouts
                  .setTimeout(timeoutName, timeout(HeartbeatMessage.sendHeartbeat, message, to));
            }
            break;
          }

        case suspicions:
          {
            HeartbeatMessage.SuspicionsState suspicions = message.getPayload();
            context
                .getClusterContext()
                .getLogger(HeartbeatState.class)
                .debug("Received suspicions as " + suspicions);

            URI from = new URI(message.getHeader(Message.FROM));
            InstanceId fromId = context.getClusterContext().getConfiguration().getServerId(from);
            /*
             * Remove ourselves from the suspicions received - we just received a message,
             * it's not normal to be considered failed. Whatever it was, it was transient and now it has
             * passed.
             */
            suspicions.getSuspicions().remove(context.getClusterContext().getMyId());
            context.suspicions(fromId, suspicions.getSuspicions());

            break;
          }

        case leave:
          {
            context.getClusterContext().getLogger(HeartbeatState.class).debug("Received leave");
            return start;
          }

        case addHeartbeatListener:
          {
            context.addHeartbeatListener((HeartbeatListener) message.getPayload());
            break;
          }

        case removeHeartbeatListener:
          {
            context.removeHeartbeatListener((HeartbeatListener) message.getPayload());
            break;
          }
      }

      return this;
    }