/** send operation to the given node or perform it if local */ void performOnReplica(final ShardRouting shard, final String nodeId) { // if we don't have that node, it means that it might have failed and will be created again, // in // this case, we don't have to do the operation, and just let it failover if (!observer.observedState().nodes().nodeExists(nodeId)) { onReplicaFailure(nodeId, null); return; } replicaRequest.internalShardId = shardIt.shardId(); if (!nodeId.equals(observer.observedState().nodes().localNodeId())) { final DiscoveryNode node = observer.observedState().nodes().get(nodeId); transportService.sendRequest( node, transportReplicaAction, replicaRequest, transportOptions, new EmptyTransportResponseHandler(ThreadPool.Names.SAME) { @Override public void handleResponse(TransportResponse.Empty vResponse) { onReplicaSuccess(); } @Override public void handleException(TransportException exp) { logger.trace( "[{}] transport failure during replica request [{}] ", exp, node, replicaRequest); if (ignoreReplicaException(exp)) { onReplicaFailure(nodeId, exp); } else { logger.warn( "{} failed to perform {} on node {}", exp, shardIt.shardId(), actionName, node); shardStateAction.shardFailed( shard, indexMetaData.getIndexUUID(), "failed to perform " + actionName + " on replica on node " + node, exp, shardFailedTimeout, new ReplicationFailedShardStateListener(nodeId, exp)); } } }); } else { try { threadPool .executor(executor) .execute( new AbstractRunnable() { @Override protected void doRun() { try { shardOperationOnReplica(shard.shardId(), replicaRequest); onReplicaSuccess(); } catch (Throwable e) { onReplicaFailure(nodeId, e); failReplicaIfNeeded(shard.index(), shard.id(), e); } } // we must never reject on because of thread pool capacity on replicas @Override public boolean isForceExecution() { return true; } @Override public void onFailure(Throwable t) { onReplicaFailure(nodeId, t); } }); } catch (Throwable e) { failReplicaIfNeeded(shard.index(), shard.id(), e); onReplicaFailure(nodeId, e); } } }