use of io.pravega.common.util.RetriesExhaustedException in project pravega by pravega.
the class ScaleOperationTask method execute.
@Override
public CompletableFuture<Void> execute(final ScaleOpEvent request) {
CompletableFuture<Void> result = new CompletableFuture<>();
final OperationContext context = streamMetadataStore.createContext(request.getScope(), request.getStream());
log.info("starting scale request for {}/{} segments {} to new ranges {}", request.getScope(), request.getStream(), request.getSegmentsToSeal(), request.getNewRanges());
streamMetadataTasks.startScale(request, request.isRunOnlyIfStarted(), context, this.streamMetadataTasks.retrieveDelegationToken()).whenCompleteAsync((res, e) -> {
if (e != null) {
Throwable cause = Exceptions.unwrap(e);
if (cause instanceof RetriesExhaustedException) {
cause = cause.getCause();
}
log.warn("processing scale request for {}/{} segments {} failed {}", request.getScope(), request.getStream(), request.getSegmentsToSeal(), cause);
result.completeExceptionally(cause);
} else {
log.info("scale request for {}/{} segments {} to new ranges {} completed successfully.", request.getScope(), request.getStream(), request.getSegmentsToSeal(), request.getNewRanges());
result.complete(null);
}
}, executor);
return result;
}
use of io.pravega.common.util.RetriesExhaustedException in project pravega by pravega.
the class BookKeeperLog method processPendingWrites.
/**
* Executes pending Writes to BookKeeper. This method is not thread safe and should only be invoked as part of
* the Write Processor.
* @return True if the no errors, false if at least one write failed.
*/
private boolean processPendingWrites() {
long traceId = LoggerHelpers.traceEnterWithContext(log, this.traceObjectId, "processPendingWrites");
// Clean up the write queue of all finished writes that are complete (successfully or failed for good)
val cs = this.writes.removeFinishedWrites();
if (cs.contains(WriteQueue.CleanupStatus.WriteFailed)) {
// We encountered a failed write. As such, we must close immediately and not process anything else.
// Closing will automatically cancel all pending writes.
close();
LoggerHelpers.traceLeave(log, this.traceObjectId, "processPendingWrites", traceId, WriteQueue.CleanupStatus.WriteFailed);
return false;
} else if (cs.contains(WriteQueue.CleanupStatus.QueueEmpty)) {
// Queue is empty - nothing else to do.
LoggerHelpers.traceLeave(log, this.traceObjectId, "processPendingWrites", traceId, WriteQueue.CleanupStatus.QueueEmpty);
return true;
}
// Calculate how much estimated space there is in the current ledger.
final long maxTotalSize = this.config.getBkLedgerMaxSize() - getWriteLedger().ledger.getLength();
// Get the writes to execute from the queue.
List<Write> toExecute = this.writes.getWritesToExecute(maxTotalSize);
// appropriate, or retried).
if (handleClosedLedgers(toExecute)) {
// If any changes were made to the Writes in the list, re-do the search to get a more accurate list of Writes
// to execute (since some may have changed Ledgers, more writes may not be eligible for execution).
toExecute = this.writes.getWritesToExecute(maxTotalSize);
}
// Execute the writes.
log.debug("{}: Executing {} writes.", this.traceObjectId, toExecute.size());
for (int i = 0; i < toExecute.size(); i++) {
Write w = toExecute.get(i);
try {
// Record the beginning of a new attempt.
int attemptCount = w.beginAttempt();
if (attemptCount > this.config.getMaxWriteAttempts()) {
// Retried too many times.
throw new RetriesExhaustedException(w.getFailureCause());
}
// Invoke the BookKeeper write.
w.getWriteLedger().ledger.asyncAddEntry(w.data.array(), w.data.arrayOffset(), w.data.getLength(), this::addCallback, w);
} catch (Throwable ex) {
// Synchronous failure (or RetriesExhausted). Fail current write.
boolean isFinal = !isRetryable(ex);
w.fail(ex, isFinal);
// And fail all remaining writes as well.
for (int j = i + 1; j < toExecute.size(); j++) {
toExecute.get(j).fail(new DurableDataLogException("Previous write failed.", ex), isFinal);
}
LoggerHelpers.traceLeave(log, this.traceObjectId, "processPendingWrites", traceId, i);
return false;
}
}
// After every run where we did write, check if need to trigger a rollover.
this.rolloverProcessor.runAsync();
LoggerHelpers.traceLeave(log, this.traceObjectId, "processPendingWrites", traceId, toExecute.size());
return true;
}
use of io.pravega.common.util.RetriesExhaustedException in project pravega by pravega.
the class ControllerImplTest method testKeepAlive.
@Test
public void testKeepAlive() throws IOException, ExecutionException, InterruptedException {
// Verify that keep-alive timeout less than permissible by the server results in a failure.
NettyChannelBuilder builder = NettyChannelBuilder.forAddress("localhost", serverPort).keepAliveTime(10, TimeUnit.SECONDS);
if (testSecure) {
builder = builder.sslContext(GrpcSslContexts.forClient().trustManager(new File("../config/cert.pem")).build());
} else {
builder = builder.usePlaintext(true);
}
final ControllerImpl controller = new ControllerImpl(builder, ControllerImplConfig.builder().clientConfig(ClientConfig.builder().trustStore("../config/cert.pem").controllerURI(URI.create((testSecure ? "tls://" : "tcp://") + "localhost:" + serverPort)).build()).retryAttempts(1).build(), this.executor);
CompletableFuture<Boolean> createStreamStatus = controller.createStream(StreamConfiguration.builder().streamName("streamdelayed").scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build());
AssertExtensions.assertThrows("Should throw RetriesExhaustedException", createStreamStatus, throwable -> throwable instanceof RetriesExhaustedException);
// Verify that the same RPC with permissible keepalive time succeeds.
int serverPort2 = TestUtils.getAvailableListenPort();
NettyServerBuilder testServerBuilder = NettyServerBuilder.forPort(serverPort2).addService(testServerImpl).permitKeepAliveTime(5, TimeUnit.SECONDS);
if (testSecure) {
testServerBuilder = testServerBuilder.useTransportSecurity(new File("../config/cert.pem"), new File("../config/key.pem"));
}
Server testServer = testServerBuilder.build().start();
builder = NettyChannelBuilder.forAddress("localhost", serverPort2).keepAliveTime(10, TimeUnit.SECONDS);
if (testSecure) {
builder = builder.sslContext(GrpcSslContexts.forClient().trustManager(new File("../config/cert.pem")).build());
} else {
builder = builder.usePlaintext(true);
}
final ControllerImpl controller1 = new ControllerImpl(builder, ControllerImplConfig.builder().clientConfig(ClientConfig.builder().trustStore("../config/cert.pem").controllerURI(URI.create((testSecure ? "tls://" : "tcp://") + "localhost:" + serverPort)).build()).retryAttempts(1).build(), this.executor);
createStreamStatus = controller1.createStream(StreamConfiguration.builder().streamName("streamdelayed").scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build());
assertTrue(createStreamStatus.get());
testServer.shutdownNow();
}
use of io.pravega.common.util.RetriesExhaustedException in project pravega by pravega.
the class SequentialAsyncProcessorTests method testRunAsyncErrors.
/**
* Tests the runAsync() method with execution errors.
*/
@Test(timeout = TIMEOUT_MILLIS)
public void testRunAsyncErrors() throws Exception {
final int expectedCount = 2;
val count = new AtomicInteger();
val finished = new CompletableFuture<Void>();
val retry = Retry.withExpBackoff(1, 2, expectedCount).retryWhen(t -> {
if (count.get() >= expectedCount) {
finished.complete(null);
}
return Exceptions.unwrap(t) instanceof IntentionalException;
}).throwingOn(Exception.class);
val error = new CompletableFuture<Throwable>();
val p = new SequentialAsyncProcessor(() -> {
count.incrementAndGet();
throw new IntentionalException();
}, retry, error::complete, executorService());
// Invoke it once.
p.runAsync();
finished.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
val finalException = Exceptions.unwrap(error.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
Assert.assertEquals("Unexpected number of final invocations.", expectedCount, count.get());
Assert.assertTrue("Unexpected final error callback.", finalException instanceof RetriesExhaustedException && Exceptions.unwrap(finalException.getCause()) instanceof IntentionalException);
}
use of io.pravega.common.util.RetriesExhaustedException in project pravega by pravega.
the class BookKeeperLogTests method testAutoCloseOnBookieFailure.
/**
* Tests the ability to auto-close upon a permanent write failure caused by BookKeeper.
*
* @throws Exception If one got thrown.
*/
@Test
public void testAutoCloseOnBookieFailure() throws Exception {
try (DurableDataLog log = createDurableDataLog()) {
log.initialize(TIMEOUT);
try {
// Suspend a bookie (this will trigger write errors).
stopFirstBookie();
// First write should fail. Either a DataLogNotAvailableException (insufficient bookies) or
// WriteFailureException (general unable to write) should be thrown.
AssertExtensions.assertThrows("First write did not fail with the appropriate exception.", () -> log.append(new ByteArraySegment(getWriteData()), TIMEOUT), ex -> ex instanceof RetriesExhaustedException && (ex.getCause() instanceof DataLogNotAvailableException || isLedgerClosedException(ex.getCause())) || ex instanceof ObjectClosedException || ex instanceof CancellationException);
// Subsequent writes should be rejected since the BookKeeperLog is now closed.
AssertExtensions.assertThrows("Second write did not fail with the appropriate exception.", () -> log.append(new ByteArraySegment(getWriteData()), TIMEOUT), ex -> ex instanceof ObjectClosedException || ex instanceof CancellationException);
} finally {
// Don't forget to resume the bookie.
restartFirstBookie();
}
}
}
Aggregations