Search in sources :

Example 11 with NodeConnectionStatus

use of org.apache.nifi.cluster.coordination.node.NodeConnectionStatus in project nifi by apache.

the class StandardFlowService method loadFromConnectionResponse.

private void loadFromConnectionResponse(final ConnectionResponse response) throws ConnectionException {
    writeLock.lock();
    try {
        if (response.getNodeConnectionStatuses() != null) {
            clusterCoordinator.resetNodeStatuses(response.getNodeConnectionStatuses().stream().collect(Collectors.toMap(status -> status.getNodeIdentifier(), status -> status)));
        }
        // get the dataflow from the response
        final DataFlow dataFlow = response.getDataFlow();
        if (logger.isTraceEnabled()) {
            logger.trace("ResponseFlow = " + new String(dataFlow.getFlow(), StandardCharsets.UTF_8));
        }
        // load new controller state
        loadFromBytes(dataFlow, true);
        // set node ID on controller before we start heartbeating because heartbeat needs node ID
        nodeId = response.getNodeIdentifier();
        logger.info("Setting Flow Controller's Node ID: " + nodeId);
        controller.setNodeId(nodeId);
        clusterCoordinator.setLocalNodeIdentifier(nodeId);
        clusterCoordinator.setConnected(true);
        revisionManager.reset(response.getComponentRevisions().stream().map(rev -> rev.toRevision()).collect(Collectors.toList()));
        // mark the node as clustered
        controller.setClustered(true, response.getInstanceId());
        controller.setConnectionStatus(new NodeConnectionStatus(nodeId, NodeConnectionState.CONNECTED));
        // Initialize the controller after the flow is loaded so we don't take any actions on repos until everything is good
        initializeController();
        // start the processors as indicated by the dataflow
        controller.onFlowInitialized(autoResumeState);
        loadSnippets(dataFlow.getSnippets());
        controller.startHeartbeating();
    } catch (final UninheritableFlowException ufe) {
        throw new UninheritableFlowException(CONNECTION_EXCEPTION_MSG_PREFIX + "local flow is different than cluster flow.", ufe);
    } catch (final MissingBundleException mbe) {
        throw new MissingBundleException(CONNECTION_EXCEPTION_MSG_PREFIX + "cluster flow contains bundles that do not exist on the current node", mbe);
    } catch (final FlowSerializationException fse) {
        throw new ConnectionException(CONNECTION_EXCEPTION_MSG_PREFIX + "local or cluster flow is malformed.", fse);
    } catch (final FlowSynchronizationException fse) {
        throw new FlowSynchronizationException(CONNECTION_EXCEPTION_MSG_PREFIX + "local flow controller partially updated. " + "Administrator should disconnect node and review flow for corruption.", fse);
    } catch (final Exception ex) {
        throw new ConnectionException("Failed to connect node to cluster due to: " + ex, ex);
    } finally {
        writeLock.unlock();
    }
}
Also used : FlowSynchronizationException(org.apache.nifi.controller.serialization.FlowSynchronizationException) FlowSerializationException(org.apache.nifi.controller.serialization.FlowSerializationException) StandardDataFlow(org.apache.nifi.cluster.protocol.StandardDataFlow) DataFlow(org.apache.nifi.cluster.protocol.DataFlow) NodeConnectionStatus(org.apache.nifi.cluster.coordination.node.NodeConnectionStatus) ConnectionException(org.apache.nifi.cluster.ConnectionException) FlowSerializationException(org.apache.nifi.controller.serialization.FlowSerializationException) ConnectionException(org.apache.nifi.cluster.ConnectionException) FlowSynchronizationException(org.apache.nifi.controller.serialization.FlowSynchronizationException) LifeCycleStartException(org.apache.nifi.lifecycle.LifeCycleStartException) NoClusterCoordinatorException(org.apache.nifi.cluster.exception.NoClusterCoordinatorException) IOException(java.io.IOException) ProtocolException(org.apache.nifi.cluster.protocol.ProtocolException)

Example 12 with NodeConnectionStatus

use of org.apache.nifi.cluster.coordination.node.NodeConnectionStatus in project nifi by apache.

the class StandardFlowService method load.

@Override
public void load(final DataFlow dataFlow) throws IOException, FlowSerializationException, FlowSynchronizationException, UninheritableFlowException, MissingBundleException {
    if (configuredForClustering) {
        // Create the initial flow from disk if it exists, or from serializing the empty root group in flow controller
        final DataFlow initialFlow = (dataFlow == null) ? createDataFlow() : dataFlow;
        if (logger.isTraceEnabled()) {
            logger.trace("InitialFlow = " + new String(initialFlow.getFlow(), StandardCharsets.UTF_8));
        }
        // Sync the initial flow into the flow controller so that if the flow came from disk we loaded the
        // whole flow into the flow controller and applied any bundle upgrades
        writeLock.lock();
        try {
            loadFromBytes(initialFlow, true);
        } finally {
            writeLock.unlock();
        }
        // Get the proposed flow by serializing the flow controller which now has the synced version from above
        final DataFlow proposedFlow = createDataFlowFromController();
        if (logger.isTraceEnabled()) {
            logger.trace("ProposedFlow = " + new String(proposedFlow.getFlow(), StandardCharsets.UTF_8));
        }
        /*
             * Attempt to connect to the cluster. If the manager is able to
             * provide a data flow, then the manager will send a connection
             * response. If the manager was unable to be located, then
             * the response will be null and we should load the local dataflow
             * and heartbeat until a manager is located.
             */
        final boolean localFlowEmpty = StandardFlowSynchronizer.isEmpty(proposedFlow);
        final ConnectionResponse response = connect(true, localFlowEmpty, proposedFlow);
        // obtain write lock while we are updating the controller. We need to ensure that we don't
        // obtain the lock before calling connect(), though, or we will end up getting a deadlock
        // because the node that is receiving the connection request won't be able to get the current
        // flow, as that requires a read lock.
        writeLock.lock();
        try {
            if (response == null || response.shouldTryLater()) {
                logger.info("Flow controller will load local dataflow and suspend connection handshake until a cluster connection response is received.");
                // set node ID on controller before we start heartbeating because heartbeat needs node ID
                controller.setNodeId(nodeId);
                clusterCoordinator.setLocalNodeIdentifier(nodeId);
                // set node as clustered, since it is trying to connect to a cluster
                controller.setClustered(true, null);
                clusterCoordinator.setConnected(false);
                controller.setConnectionStatus(new NodeConnectionStatus(nodeId, DisconnectionCode.NOT_YET_CONNECTED));
                /*
                     * Start heartbeating. Heartbeats will fail because we can't reach
                     * the manager, but when we locate the manager, the node will
                     * reconnect and establish a connection to the cluster. The
                     * heartbeat is the trigger that will cause the manager to
                     * issue a reconnect request.
                     */
                controller.startHeartbeating();
                // Initialize the controller after the flow is loaded so we don't take any actions on repos until everything is good
                initializeController();
                // notify controller that flow is initialized
                try {
                    controller.onFlowInitialized(autoResumeState);
                } catch (final Exception ex) {
                    logger.warn("Unable to start all processors due to invalid flow configuration.");
                    if (logger.isDebugEnabled()) {
                        logger.warn(StringUtils.EMPTY, ex);
                    }
                }
            } else {
                try {
                    loadFromConnectionResponse(response);
                } catch (final Exception e) {
                    logger.error("Failed to load flow from cluster due to: " + e, e);
                    handleConnectionFailure(e);
                    throw new IOException(e);
                }
            }
            // save the flow in the controller so we write out the latest flow with any updated bundles to disk
            dao.save(controller, true);
        } finally {
            writeLock.unlock();
        }
    } else {
        writeLock.lock();
        try {
            // operating in standalone mode, so load proposed flow and initialize the controller
            loadFromBytes(dataFlow, true);
            initializeController();
            dao.save(controller, true);
        } finally {
            writeLock.unlock();
        }
    }
}
Also used : IOException(java.io.IOException) ConnectionResponse(org.apache.nifi.cluster.protocol.ConnectionResponse) StandardDataFlow(org.apache.nifi.cluster.protocol.StandardDataFlow) DataFlow(org.apache.nifi.cluster.protocol.DataFlow) NodeConnectionStatus(org.apache.nifi.cluster.coordination.node.NodeConnectionStatus) FlowSerializationException(org.apache.nifi.controller.serialization.FlowSerializationException) ConnectionException(org.apache.nifi.cluster.ConnectionException) FlowSynchronizationException(org.apache.nifi.controller.serialization.FlowSynchronizationException) LifeCycleStartException(org.apache.nifi.lifecycle.LifeCycleStartException) NoClusterCoordinatorException(org.apache.nifi.cluster.exception.NoClusterCoordinatorException) IOException(java.io.IOException) ProtocolException(org.apache.nifi.cluster.protocol.ProtocolException)

Example 13 with NodeConnectionStatus

use of org.apache.nifi.cluster.coordination.node.NodeConnectionStatus in project nifi by apache.

the class ClusterProtocolHeartbeater method send.

@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);
}
Also used : HeartbeatResponseMessage(org.apache.nifi.cluster.protocol.message.HeartbeatResponseMessage) ClusterRoles(org.apache.nifi.cluster.coordination.node.ClusterRoles) NodeProtocolSender(org.apache.nifi.cluster.protocol.NodeProtocolSender) HeartbeatResponseMessage(org.apache.nifi.cluster.protocol.message.HeartbeatResponseMessage) LeaderElectionManager(org.apache.nifi.controller.leader.election.LeaderElectionManager) NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) Logger(org.slf4j.Logger) Date(java.util.Date) HeartbeatPayload(org.apache.nifi.cluster.protocol.HeartbeatPayload) LoggerFactory(org.slf4j.LoggerFactory) SimpleDateFormat(java.text.SimpleDateFormat) IOException(java.io.IOException) Collectors(java.util.stream.Collectors) HeartbeatMessage(org.apache.nifi.cluster.protocol.message.HeartbeatMessage) TimeUnit(java.util.concurrent.TimeUnit) List(java.util.List) ProtocolException(org.apache.nifi.cluster.protocol.ProtocolException) Locale(java.util.Locale) Map(java.util.Map) ClusterCoordinator(org.apache.nifi.cluster.coordination.ClusterCoordinator) DateFormat(java.text.DateFormat) NodeConnectionStatus(org.apache.nifi.cluster.coordination.node.NodeConnectionStatus) NodeConnectionStatus(org.apache.nifi.cluster.coordination.node.NodeConnectionStatus) Date(java.util.Date) NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) SimpleDateFormat(java.text.SimpleDateFormat) DateFormat(java.text.DateFormat) HeartbeatPayload(org.apache.nifi.cluster.protocol.HeartbeatPayload) SimpleDateFormat(java.text.SimpleDateFormat)

Example 14 with NodeConnectionStatus

use of org.apache.nifi.cluster.coordination.node.NodeConnectionStatus in project nifi by apache.

the class TestJaxbProtocolUtils method testRoundTripHeartbeat.

@Test
public void testRoundTripHeartbeat() throws JAXBException {
    final NodeIdentifier nodeId = new NodeIdentifier("id", "localhost", 8000, "localhost", 8001, "localhost", 8002, 8003, true);
    final NodeConnectionStatus nodeStatus = new NodeConnectionStatus(nodeId, DisconnectionCode.NOT_YET_CONNECTED);
    final HeartbeatPayload payload = new HeartbeatPayload();
    payload.setActiveThreadCount(1);
    payload.setSystemStartTime(System.currentTimeMillis());
    payload.setTotalFlowFileBytes(83L);
    payload.setTotalFlowFileCount(4);
    final List<NodeConnectionStatus> clusterStatus = Collections.singletonList(nodeStatus);
    payload.setClusterStatus(clusterStatus);
    final Heartbeat heartbeat = new Heartbeat(nodeId, nodeStatus, payload.marshal());
    final HeartbeatMessage msg = new HeartbeatMessage();
    msg.setHeartbeat(heartbeat);
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    JaxbProtocolUtils.JAXB_CONTEXT.createMarshaller().marshal(msg, baos);
    final Object unmarshalled = JaxbProtocolUtils.JAXB_CONTEXT.createUnmarshaller().unmarshal(new ByteArrayInputStream(baos.toByteArray()));
    assertTrue(unmarshalled instanceof HeartbeatMessage);
}
Also used : HeartbeatMessage(org.apache.nifi.cluster.protocol.message.HeartbeatMessage) ByteArrayInputStream(java.io.ByteArrayInputStream) NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) Heartbeat(org.apache.nifi.cluster.protocol.Heartbeat) HeartbeatPayload(org.apache.nifi.cluster.protocol.HeartbeatPayload) ByteArrayOutputStream(java.io.ByteArrayOutputStream) NodeConnectionStatus(org.apache.nifi.cluster.coordination.node.NodeConnectionStatus) Test(org.junit.Test)

Example 15 with NodeConnectionStatus

use of org.apache.nifi.cluster.coordination.node.NodeConnectionStatus in project nifi by apache.

the class TestJaxbProtocolUtils method testRoundTripConnectionResponse.

@Test
public void testRoundTripConnectionResponse() throws JAXBException {
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    final ConnectionResponseMessage msg = new ConnectionResponseMessage();
    final NodeIdentifier nodeId = new NodeIdentifier("id", "localhost", 8000, "localhost", 8001, "localhost", 8002, 8003, true);
    final DataFlow dataFlow = new StandardDataFlow(new byte[0], new byte[0], new byte[0], new HashSet<>());
    final List<NodeConnectionStatus> nodeStatuses = Collections.singletonList(new NodeConnectionStatus(nodeId, DisconnectionCode.NOT_YET_CONNECTED));
    final List<ComponentRevision> componentRevisions = Collections.singletonList(ComponentRevision.fromRevision(new Revision(8L, "client-1", "component-1")));
    msg.setConnectionResponse(new ConnectionResponse(nodeId, dataFlow, "instance-1", nodeStatuses, componentRevisions));
    JaxbProtocolUtils.JAXB_CONTEXT.createMarshaller().marshal(msg, baos);
    final Object unmarshalled = JaxbProtocolUtils.JAXB_CONTEXT.createUnmarshaller().unmarshal(new ByteArrayInputStream(baos.toByteArray()));
    assertTrue(unmarshalled instanceof ConnectionResponseMessage);
    final ConnectionResponseMessage unmarshalledMsg = (ConnectionResponseMessage) unmarshalled;
    final List<ComponentRevision> revisions = msg.getConnectionResponse().getComponentRevisions();
    assertEquals(1, revisions.size());
    assertEquals(8L, revisions.get(0).getVersion().longValue());
    assertEquals("client-1", revisions.get(0).getClientId());
    assertEquals("component-1", revisions.get(0).getComponentId());
    assertEquals(revisions, unmarshalledMsg.getConnectionResponse().getComponentRevisions());
}
Also used : ByteArrayOutputStream(java.io.ByteArrayOutputStream) ConnectionResponse(org.apache.nifi.cluster.protocol.ConnectionResponse) DataFlow(org.apache.nifi.cluster.protocol.DataFlow) StandardDataFlow(org.apache.nifi.cluster.protocol.StandardDataFlow) NodeConnectionStatus(org.apache.nifi.cluster.coordination.node.NodeConnectionStatus) ComponentRevision(org.apache.nifi.cluster.protocol.ComponentRevision) Revision(org.apache.nifi.web.Revision) ComponentRevision(org.apache.nifi.cluster.protocol.ComponentRevision) StandardDataFlow(org.apache.nifi.cluster.protocol.StandardDataFlow) ByteArrayInputStream(java.io.ByteArrayInputStream) NodeIdentifier(org.apache.nifi.cluster.protocol.NodeIdentifier) ConnectionResponseMessage(org.apache.nifi.cluster.protocol.message.ConnectionResponseMessage) Test(org.junit.Test)

Aggregations

NodeConnectionStatus (org.apache.nifi.cluster.coordination.node.NodeConnectionStatus)16 NodeIdentifier (org.apache.nifi.cluster.protocol.NodeIdentifier)12 ClusterCoordinator (org.apache.nifi.cluster.coordination.ClusterCoordinator)5 Test (org.junit.Test)5 HashMap (java.util.HashMap)4 Map (java.util.Map)4 ProtocolException (org.apache.nifi.cluster.protocol.ProtocolException)4 ByteArrayInputStream (java.io.ByteArrayInputStream)3 ByteArrayOutputStream (java.io.ByteArrayOutputStream)3 IOException (java.io.IOException)3 List (java.util.List)3 NodeConnectionState (org.apache.nifi.cluster.coordination.node.NodeConnectionState)3 DataFlow (org.apache.nifi.cluster.protocol.DataFlow)3 HeartbeatPayload (org.apache.nifi.cluster.protocol.HeartbeatPayload)3 StandardDataFlow (org.apache.nifi.cluster.protocol.StandardDataFlow)3 HeartbeatMessage (org.apache.nifi.cluster.protocol.message.HeartbeatMessage)3 URI (java.net.URI)2 URISyntaxException (java.net.URISyntaxException)2 Collections (java.util.Collections)2 HashSet (java.util.HashSet)2