use of org.apache.nifi.cluster.protocol.NodeIdentifier in project nifi by apache.
the class ThreadPoolRequestReplicator method submitAsyncRequest.
private void submitAsyncRequest(final Set<NodeIdentifier> nodeIds, final String scheme, final String path, final Function<NodeIdentifier, NodeHttpRequest> callableFactory, final Map<String, String> headers) {
if (nodeIds.isEmpty()) {
// return quickly for trivial case
return;
}
// submit the requests to the nodes
for (final NodeIdentifier nodeId : nodeIds) {
final NodeHttpRequest callable = callableFactory.apply(nodeId);
executorService.submit(callable);
}
}
use of org.apache.nifi.cluster.protocol.NodeIdentifier in project nifi by apache.
the class ThreadPoolRequestReplicator method onCompletedResponse.
/**
* When all nodes have completed a request and provided a response (or have timed out), this method will be invoked
* to handle calling the Callback that was provided for the request, if any, and handle any cleanup or post-processing
* related to the request
*
* @param requestId the ID of the request that has completed
*/
private void onCompletedResponse(final String requestId) {
final AsyncClusterResponse response = responseMap.get(requestId);
if (response != null && callback != null) {
try {
callback.afterRequest(response.getURIPath(), response.getMethod(), response.getCompletedNodeResponses());
} catch (final Exception e) {
logger.warn("Completed request {} {} but failed to properly handle the Request Completion Callback due to {}", response.getMethod(), response.getURIPath(), e.toString());
logger.warn("", e);
}
}
if (response != null && logger.isDebugEnabled()) {
logTimingInfo(response);
}
// If we have any nodes that are slow to respond, keep track of this. If the same node is slow 3 times in
// a row, log a warning to indicate that the node is responding slowly.
final Set<NodeIdentifier> slowResponseNodes = ResponseUtils.findLongResponseTimes(response, 1.5D);
for (final NodeIdentifier nodeId : response.getNodesInvolved()) {
final AtomicInteger counter = sequentialLongRequestCounts.computeIfAbsent(nodeId, id -> new AtomicInteger(0));
if (slowResponseNodes.contains(nodeId)) {
final int sequentialLongRequests = counter.incrementAndGet();
if (sequentialLongRequests >= 3) {
final String message = "Response time from " + nodeId + " was slow for each of the last 3 requests made. " + "To see more information about timing, enable DEBUG logging for " + logger.getName();
logger.warn(message);
if (eventReporter != null) {
eventReporter.reportEvent(Severity.WARNING, "Node Response Time", message);
}
counter.set(0);
}
} else {
counter.set(0);
}
}
}
use of org.apache.nifi.cluster.protocol.NodeIdentifier in project nifi by apache.
the class NodeClusterCoordinator method resetNodeStatus.
@Override
public boolean resetNodeStatus(final NodeConnectionStatus connectionStatus, final long qualifyingUpdateId) {
final NodeIdentifier nodeId = connectionStatus.getNodeIdentifier();
final NodeConnectionStatus currentStatus = getConnectionStatus(nodeId);
if (currentStatus == null) {
return replaceNodeStatus(nodeId, null, connectionStatus);
} else if (currentStatus.getUpdateIdentifier() == qualifyingUpdateId) {
return replaceNodeStatus(nodeId, currentStatus, connectionStatus);
}
// The update identifier is not the same. We will not replace the value
return false;
}
use of org.apache.nifi.cluster.protocol.NodeIdentifier in project nifi by apache.
the class NodeClusterCoordinator method afterRequest.
/**
* Callback that is called after an HTTP Request has been replicated to
* nodes in the cluster. This allows us to disconnect nodes that did not
* complete the request, if applicable.
*/
@Override
public void afterRequest(final String uriPath, final String method, final Set<NodeResponse> nodeResponses) {
// as the cluster coordinator is responsible for performing the actual request replication.
if (!isActiveClusterCoordinator()) {
return;
}
final boolean mutableRequest = isMutableRequest(method);
/*
* Nodes that encountered issues handling the request are marked as
* disconnected for mutable requests (e.g., post, put, delete). For
* other requests (e.g., get, head), the nodes remain in their current
* state even if they had problems handling the request.
*/
if (mutableRequest) {
final HttpResponseMapper responseMerger = new StandardHttpResponseMapper(nifiProperties);
final Set<NodeResponse> problematicNodeResponses = responseMerger.getProblematicNodeResponses(nodeResponses);
// all nodes failed
final boolean allNodesFailed = problematicNodeResponses.size() == nodeResponses.size();
// some nodes had a problematic response because of a missing counter, ensure the are not disconnected
final boolean someNodesFailedMissingCounter = !problematicNodeResponses.isEmpty() && problematicNodeResponses.size() < nodeResponses.size() && isMissingCounter(problematicNodeResponses, uriPath);
// ensure nodes stay connected in certain scenarios
if (allNodesFailed) {
logger.warn("All nodes failed to process URI {} {}. As a result, no node will be disconnected from cluster", method, uriPath);
return;
}
if (someNodesFailedMissingCounter) {
return;
}
// disconnect problematic nodes
if (!problematicNodeResponses.isEmpty() && problematicNodeResponses.size() < nodeResponses.size()) {
final Set<NodeIdentifier> failedNodeIds = problematicNodeResponses.stream().map(response -> response.getNodeId()).collect(Collectors.toSet());
logger.warn(String.format("The following nodes failed to process URI %s '%s'. Requesting each node disconnect from cluster.", uriPath, failedNodeIds));
for (final NodeIdentifier nodeId : failedNodeIds) {
requestNodeDisconnect(nodeId, DisconnectionCode.FAILED_TO_SERVICE_REQUEST, "Failed to process request " + method + " " + uriPath);
}
}
}
}
use of org.apache.nifi.cluster.protocol.NodeIdentifier in project nifi by apache.
the class NodeClusterCoordinator method handleNodeStatusChange.
private void handleNodeStatusChange(final NodeStatusChangeMessage statusChangeMessage) {
final NodeConnectionStatus updatedStatus = statusChangeMessage.getNodeConnectionStatus();
final NodeIdentifier nodeId = statusChangeMessage.getNodeId();
logger.debug("Handling request {}", statusChangeMessage);
final NodeConnectionStatus oldStatus = nodeStatuses.get(statusChangeMessage.getNodeId());
// Either remove the value from the map or update the map depending on the connection state
if (statusChangeMessage.getNodeConnectionStatus().getState() == NodeConnectionState.REMOVED) {
nodeStatuses.remove(nodeId, oldStatus);
} else {
nodeStatuses.put(nodeId, updatedStatus);
}
logger.info("Status of {} changed from {} to {}", statusChangeMessage.getNodeId(), oldStatus, updatedStatus);
logger.debug("State of cluster nodes is now {}", nodeStatuses);
final NodeConnectionStatus status = statusChangeMessage.getNodeConnectionStatus();
final String summary = summarizeStatusChange(oldStatus, status);
if (!StringUtils.isEmpty(summary)) {
addNodeEvent(nodeId, summary);
}
// Update our counter so that we are in-sync with the cluster on the
// most up-to-date version of the NodeConnectionStatus' Update Identifier.
// We do this so that we can accurately compare status updates that are generated
// locally against those generated from other nodes in the cluster.
NodeConnectionStatus.updateIdGenerator(updatedStatus.getUpdateIdentifier());
if (isActiveClusterCoordinator()) {
notifyOthersOfNodeStatusChange(statusChangeMessage.getNodeConnectionStatus());
}
}
Aggregations