if (!canRetry(ex)) {
return READ_RETRY.runAsync(() -> this.index.get(serializedKeys, timeout), this.executor) .thenApply(entries -> { assert entries.size() == keys.size() : "Unexpected number of entries returned by the index search.";
DISABLE_RETRY.run(() -> { output("Acquiring ownership (attempt %d/%d) ...", count.incrementAndGet(), MAX_RETRIES); log.disable();
.thenRun(() -> isDone.set(true)) // We are done. .exceptionally(ex -> { if (!canRetry(ex)) {
@SuppressWarnings("unchecked") public <RetryT extends Exception, ReturnT> ReturnT run(Retryable<ReturnT, RetryT, ThrowsT> r) throws ThrowsT { Preconditions.checkNotNull(r); long delay = params.initialMillis; Exception last = null; for (int attemptNumber = 1; attemptNumber <= params.attempts; attemptNumber++) { try { return r.attempt(); } catch (Exception e) { if (canRetry(e)) { last = e; } else if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { throw (ThrowsT) e; } } if (attemptNumber < params.attempts) { // no need to sleep if it is the last attempt final long sleepFor = delay; Exceptions.handleInterrupted(() -> Thread.sleep(sleepFor)); delay = Math.min(params.maxDelay, params.multiplier * delay); log.debug("Retrying command. Retry #{}, timestamp={}", attemptNumber, Instant.now()); } } throw new RetriesExhaustedException(last); }
@SneakyThrows private void readNextItem(Consumer<ReadItem> eventHandler) { int readAttempts = MAX_READ_ATTEMPTS; long timeoutMillis = ClientReader.this.testConfig.getTimeout().toMillis(); while (readAttempts-- > 0) { EventRead<byte[]> readResult = READ_RETRY.run(() -> getReader().readNextEvent(timeoutMillis)); if (readResult.getEvent() == null && readAttempts > 0) { // EventStreamReader.readNextEvent() will return null if we get no new events within the given timeout. // Retry the read up to the maximum allowed number of times before giving up. Thread.sleep(timeoutMillis / MAX_READ_ATTEMPTS); } else if (readResult.getEvent() == null) { // We are done. close(); return; } else { StreamReadItem readItem = toReadItem(readResult.getEvent(), readResult.getEventPointer()); eventHandler.accept(readItem); return; } } }
@Override public CompletableFuture<List<Map.Entry<UUID, Long>>> getNext() { return READ_RETRY .runAsync(this::getNextPageEntries, executor) .thenApply(pageEntries -> { if (pageEntries == null) { // We are done. return null; } val result = pageEntries.stream() .map(e -> Maps.immutableEntry(deserializeKey(e.getKey()), deserializeValue(e.getValue()))) .collect(Collectors.toList()); if (result.size() > 0) { // Update the last Attribute Id and also indicate that we have processed at least one iteration. this.lastProcessedId.set(result.get(result.size() - 1).getKey()); this.firstInvocation.set(false); } return result; }) .exceptionally(SegmentAttributeBTreeIndex.this::handleIndexOperationException); }
private void runInternal() { this.retry.runInExecutor(this.runnable, this.executor) .whenComplete((r, ex) -> { if (ex != null) { // If we were unable to execute after all retries, invoke the failure callback. Callbacks.invokeSafely(this.failureCallback, ex, null); } boolean loopAgain; synchronized (this) { this.running = this.runAgain && !this.closed; this.runAgain = false; loopAgain = this.running; } if (loopAgain) { runInternal(); } }); }
/** * Executes the given Index Operation with retries. Retries are only performed in case of conditional update failures, * represented by BadOffsetException. * * @param indexOperation A Function, that, when invoked, returns a CompletableFuture which indicates when the index * operation completes. * @param timeout Timeout for the operation. * @return A CompletableFuture that will indicate when the operation completes. */ private CompletableFuture<Void> executeConditionally(Function<Duration, CompletableFuture<Long>> indexOperation, Duration timeout) { TimeoutTimer timer = new TimeoutTimer(timeout); return UPDATE_RETRY .runAsync(() -> executeConditionallyOnce(indexOperation, timer), this.executor) .exceptionally(this::handleIndexOperationException) .thenAccept(Callbacks::doNothing); }