private void storeState() { final ObjectMapper mapper = new ObjectMapper(); final JsonFactory jsonFactory = new JsonFactory(); jsonFactory.setCodec(mapper); try { final Map<String, String> stateMap = new HashMap<>(); final NodeIdentifier localNodeId = getLocalNodeIdentifier(); for (final NodeIdentifier nodeId : getNodeIdentifiers()) { final boolean isLocalId = nodeId.equals(localNodeId); final NodeIdentifierDescriptor descriptor = NodeIdentifierDescriptor.fromNodeIdentifier(nodeId, isLocalId); try (final StringWriter writer = new StringWriter()) { final JsonGenerator jsonGenerator = jsonFactory.createGenerator(writer); jsonGenerator.writeObject(descriptor); final String serializedDescriptor = writer.toString(); stateMap.put(nodeId.getId(), serializedDescriptor); } } stateManager.setState(stateMap, Scope.LOCAL); logger.debug("Stored the following state as the Cluster Topology: {}", stateMap); } catch (final Exception e) { logger.warn("Failed to store cluster topology to local State Manager. Upon restart of NiFi, the cluster topology may not be accurate until joining the cluster.", e); } }
@Override public void requestNodeOffload(final NodeIdentifier nodeId, final OffloadCode offloadCode, final String explanation) { final Set<NodeIdentifier> offloadNodeIds = getNodeIdentifiers(NodeConnectionState.OFFLOADING, NodeConnectionState.OFFLOADED); if (offloadNodeIds.contains(nodeId)) { logger.debug("Attempted to offload node but the node is already offloading or offloaded"); // no need to do anything here, the node is currently offloading or already offloaded return; } final Set<NodeIdentifier> disconnectedNodeIds = getNodeIdentifiers(NodeConnectionState.DISCONNECTED); if (!disconnectedNodeIds.contains(nodeId)) { throw new IllegalNodeOffloadException("Cannot offload node " + nodeId + " because it is not currently disconnected"); } logger.info("Requesting that {} is offloaded due to {}", nodeId, explanation == null ? offloadCode : explanation); updateNodeStatus(new NodeConnectionStatus(nodeId, NodeConnectionState.OFFLOADING, offloadCode, explanation)); final OffloadMessage request = new OffloadMessage(); request.setNodeId(nodeId); request.setExplanation(explanation); addNodeEvent(nodeId, "Offload requested due to " + explanation); offloadAsynchronously(request, 10, 5); }
final Set<NodeIdentifier> connectedNodeIds = getNodeIdentifiers(); final NodeIdentifier electedNodeId = connectedNodeIds.stream() .filter(nodeId -> nodeId.getSocketAddress().equals(electedNodeHostname) && nodeId.getSocketPort() == electedNodePort)
@Override public void requestNodeDisconnect(final NodeIdentifier nodeId, final DisconnectionCode disconnectionCode, final String explanation) { final Set<NodeIdentifier> connectedNodeIds = getNodeIdentifiers(NodeConnectionState.CONNECTED); if (connectedNodeIds.size() == 1 && connectedNodeIds.contains(nodeId)) { throw new IllegalNodeDisconnectionException("Cannot disconnect node " + nodeId + " because it is the only node currently connected"); } logger.info("Requesting that {} disconnect due to {}", nodeId, explanation == null ? disconnectionCode : explanation); updateNodeStatus(new NodeConnectionStatus(nodeId, disconnectionCode, explanation)); // There is no need to tell the node that it's disconnected if it is due to being // shutdown, as we will not be able to connect to the node anyway. if (disconnectionCode == DisconnectionCode.NODE_SHUTDOWN) { return; } final DisconnectMessage request = new DisconnectMessage(); request.setNodeId(nodeId); request.setExplanation(explanation); addNodeEvent(nodeId, "Disconnection requested due to " + explanation); disconnectAsynchronously(request, 10, 5); }
/** * Notifies other nodes that the status of a node changed * * @param updatedStatus the updated status for a node in the cluster * @param notifyAllNodes if <code>true</code> will notify all nodes. If * <code>false</code>, will notify only the cluster coordinator */ void notifyOthersOfNodeStatusChange(final NodeConnectionStatus updatedStatus, final boolean notifyAllNodes, final boolean waitForCoordinator) { // If this node is the active cluster coordinator, then we are going to replicate to all nodes. // Otherwise, get the active coordinator (or wait for one to become active) and then notify the coordinator. final Set<NodeIdentifier> nodesToNotify; if (notifyAllNodes) { nodesToNotify = getNodeIdentifiers(); // Do not notify ourselves because we already know about the status update. nodesToNotify.remove(getLocalNodeIdentifier()); } else if (waitForCoordinator) { nodesToNotify = Collections.singleton(waitForElectedClusterCoordinator()); } else { final NodeIdentifier nodeId = getElectedActiveCoordinatorNode(); if (nodeId == null) { return; } nodesToNotify = Collections.singleton(nodeId); } final NodeStatusChangeMessage message = new NodeStatusChangeMessage(); message.setNodeId(updatedStatus.getNodeIdentifier()); message.setNodeConnectionStatus(updatedStatus); senderListener.notifyNodeStatusChange(nodesToNotify, message); }