@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; }
@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; }