void retry(final @Nullable Throwable failure) { if (observer.isTimedOut()) { // we running as a last attempt after a timeout has happened. don't retry Throwable listenFailure = failure; if (listenFailure == null) { if (shardIt == null) { listenFailure = new UnavailableShardsException( new ShardId(request.concreteIndex(), -1), "Timeout waiting for [{}], request: {}", request.timeout(), actionName); } else { listenFailure = new UnavailableShardsException( shardIt.shardId(), "[{}] shardIt, [{}] active : Timeout waiting for [{}], request: {}", shardIt.size(), shardIt.sizeActive(), request.timeout(), actionName); } } listener.onFailure(listenFailure); return; } observer.waitForNextChange( new ClusterStateObserver.Listener() { @Override public void onNewClusterState(ClusterState state) { doStart(); } @Override public void onClusterServiceClose() { listener.onFailure(new NodeClosedException(nodes.localNode())); } @Override public void onTimeout(TimeValue timeout) { // just to be on the safe side, see if we can start it now? doStart(); } }, request.timeout()); }
protected void doStart() { nodes = observer.observedState().nodes(); try { ClusterBlockException blockException = checkGlobalBlock(observer.observedState()); if (blockException != null) { if (blockException.retryable()) { retry(blockException); return; } else { throw blockException; } } request.concreteIndex( indexNameExpressionResolver.concreteSingleIndex(observer.observedState(), request)); // check if we need to execute, and if not, return if (!resolveRequest(observer.observedState(), request, listener)) { listener.onFailure( new IllegalStateException( LoggerMessageFormat.format( "{} request {} could not be resolved", new ShardId(request.index, request.shardId), actionName))); return; } blockException = checkRequestBlock(observer.observedState(), request); if (blockException != null) { if (blockException.retryable()) { retry(blockException); return; } else { throw blockException; } } shardIt = shards(observer.observedState(), request); } catch (Throwable e) { listener.onFailure(e); return; } // no shardIt, might be in the case between index gateway recovery and shardIt initialization if (shardIt.size() == 0) { retry(null); return; } // this transport only make sense with an iterator that returns a single shard routing (like // primary) assert shardIt.size() == 1; ShardRouting shard = shardIt.nextOrNull(); assert shard != null; if (!shard.active()) { retry(null); return; } request.shardId = shardIt.shardId().id(); DiscoveryNode node = nodes.get(shard.currentNodeId()); transportService.sendRequest( node, shardActionName, request, transportOptions(), new BaseTransportResponseHandler<Response>() { @Override public Response newInstance() { return newResponse(); } @Override public String executor() { return ThreadPool.Names.SAME; } @Override public void handleResponse(Response response) { listener.onResponse(response); } @Override public void handleException(TransportException exp) { Throwable cause = exp.unwrapCause(); // if we got disconnected from the node, or the node / shard is not in the right state // (being closed) if (cause instanceof ConnectTransportException || cause instanceof NodeClosedException || retryOnFailure(exp)) { retry(cause); } else { listener.onFailure(exp); } } }); }
protected ClusterBlockException checkRequestBlock(ClusterState state, Request request) { return state.blocks().indexBlockedException(ClusterBlockLevel.WRITE, request.concreteIndex()); }