/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.cluster.coordination.http.replication;
import java.net.URI;
import java.util.Map;
import java.util.Set;
import org.apache.nifi.cluster.protocol.NodeIdentifier;
public interface RequestReplicator {
public static final String REQUEST_TRANSACTION_ID_HEADER = "X-RequestTransactionId";
public static final String CLUSTER_ID_GENERATION_SEED_HEADER = "X-Cluster-Id-Generation-Seed";
/**
* The HTTP header that the requestor specifies to ask a node if they are able to process a given request. The value
* is always 150-NodeContinue. The node will respond with 150 CONTINUE if it is able to
* process the request, 417 EXPECTATION_FAILED otherwise.
*/
public static final String REQUEST_VALIDATION_HTTP_HEADER = "X-Validation-Expects";
public static final String NODE_CONTINUE = "150-NodeContinue";
public static final int NODE_CONTINUE_STATUS_CODE = 150;
/**
* Indicates that the request is intended to cancel a transaction that was previously created without performing the action
*/
public static final String REQUEST_TRANSACTION_CANCELATION_HTTP_HEADER = "X-Cancel-Transaction";
/**
* Indicates that this is the second phase of the two phase commit and the execution of the action should proceed.
*/
public static final String REQUEST_EXECUTION_HTTP_HEADER = "X-Execution-Continue";
/**
* When we replicate a request across the cluster, we replicate it only from the cluster coordinator.
* If the request needs to be replicated by another node, it first replicates the request to the coordinator,
* which then replicates the request on the node's behalf. This header name and value are used to denote
* that the request has already been to the cluster coordinator, and the cluster coordinator is the one replicating
* the request. This allows us to know that the request should be serviced, rather than proxied back to the
* cluster coordinator.
*/
public static final String REPLICATION_INDICATOR_HEADER = "X-Request-Replicated";
/**
* When replicating a request to the cluster coordinator, it may be useful to denote that the request should
* be replicated only to a single node. This happens, for instance, when retrieving a Provenance Event that
* we know lives on a specific node. This request must still be replicated through the cluster coordinator.
* This header tells the cluster coordinator the UUID's (comma-separated list, possibly with spaces between)
* of the nodes that the request should be replicated to.
*/
public static final String REPLICATION_TARGET_NODE_UUID_HEADER = "X-Replication-Target-Id";
/**
* Stops the instance from replicating requests. Calling this method on a stopped instance has no effect.
*/
void shutdown();
/**
* Replicates a request to each node in the cluster. If the request attempts to modify the flow and there is a node
* that is not currently connected, an Exception will be thrown. Otherwise, the returned AsyncClusterResponse object
* will contain the results that are immediately available, as well as an identifier for obtaining an updated result
* later. NOTE: This method will ALWAYS indicate that the request has been replicated.
*
* @param method the HTTP method (e.g., POST, PUT)
* @param uri the base request URI (up to, but not including, the query string)
* @param entity an entity
* @param headers any HTTP headers
* @return an AsyncClusterResponse that indicates the current status of the request and provides an identifier for obtaining an updated response later
* @throws ConnectingNodeMutableRequestException if the request attempts to modify the flow and there is a node that is in the CONNECTING state
* @throws DisconnectedNodeMutableRequestException if the request attempts to modify the flow and there is a node that is in the DISCONNECTED state
*/
AsyncClusterResponse replicate(String method, URI uri, Object entity, Map<String, String> headers);
/**
* Requests are sent to each node in the given set of Node Identifiers. The returned AsyncClusterResponse object will contain
* the results that are immediately available, as well as an identifier for obtaining an updated result later.
* <p>
* HTTP DELETE, GET, HEAD, and OPTIONS methods will throw an IllegalArgumentException if used.
*
* @param nodeIds the node identifiers
* @param method the HTTP method (e.g., POST, PUT)
* @param uri the base request URI (up to, but not including, the query string)
* @param entity an entity
* @param headers any HTTP headers
* @param indicateReplicated if <code>true</code>, will add a header indicating to the receiving nodes that the request
* has already been replicated, so the receiving node will not replicate the request itself.
* @param performVerification if <code>true</code>, and the request is mutable, will verify that all nodes are connected before
* making the request and that all nodes are able to perform the request before acutally attempting to perform the task.
* If false, will perform no such verification
* @return an AsyncClusterResponse that indicates the current status of the request and provides an identifier for obtaining an updated response later
*/
AsyncClusterResponse replicate(Set<NodeIdentifier> nodeIds, String method, URI uri, Object entity, Map<String, String> headers, boolean indicateReplicated, boolean performVerification);
/**
* Forwards a request to the Cluster Coordinator so that it is able to replicate the request to all nodes in the cluster.
*
* @param coordinatorNodeId the node identifier of the Cluster Coordinator
* @param method the HTTP method (e.g., POST, PUT)
* @param uri the base request URI (up to, but not including, the query string)
* @param entity an entity
* @param headers any HTTP headers
* @return an AsyncClusterResponse that indicates the current status of the request and provides an identifier for obtaining an updated response later
*/
AsyncClusterResponse forwardToCoordinator(NodeIdentifier coordinatorNodeId, String method, URI uri, Object entity, Map<String, String> headers);
/**
* <p>
* Returns an AsyncClusterResponse that provides the most up-to-date status of the request with the given identifier.
* If the request is finished, meaning that all nodes in the cluster have reported back their status or have timed out,
* then the response will be removed and any subsequent calls to obtain the response with the same identifier will return
* <code>null</code>. If the response is not complete, the method may be called again at some point in the future in order
* to check again if the request has completed.
* </p>
*
* @param requestIdentifier the identifier of the request to obtain a response for
* @return an AsyncClusterResponse that provides the most up-to-date status of the request with the given identifier, or <code>null</code> if
* no request exists with the given identifier
*/
AsyncClusterResponse getClusterResponse(String requestIdentifier);
}