use of com.apple.foundationdb.record.RecordCoreRetriableTransactionException in project fdb-record-layer by FoundationDB.
the class FDBDatabaseRunnerTest method testRestoreMdc.
@Test
void testRestoreMdc() {
Executor oldExecutor = FDBDatabaseFactory.instance().getExecutor();
try {
ThreadContext.clearAll();
ThreadContext.put("outer", "Echidna");
final Map<String, String> outer = ThreadContext.getContext();
final ImmutableMap<String, String> restored = ImmutableMap.of("restored", "Platypus");
FDBDatabaseFactory.instance().setExecutor(new ContextRestoringExecutor(new ForkJoinPool(2), ImmutableMap.of("executor", "Water Bear")));
AtomicInteger attempts = new AtomicInteger(0);
final FDBDatabaseRunner runner = database.newRunner(FDBRecordContextConfig.newBuilder().setMdcContext(restored));
List<Map<String, String>> threadContexts = new Vector<>();
Consumer<String> saveThreadContext = name -> threadContexts.add(threadContextPlus(name, attempts.get(), ThreadContext.getContext()));
final String runnerRunAsyncName = "runner runAsync";
final String supplyAsyncName = "supplyAsync";
final String handleName = "handle";
// Delay starting the future until all callbacks have been set up so that the handle lambda
// runs in the context-restoring executor.
CompletableFuture<Void> signal = new CompletableFuture<>();
CompletableFuture<?> task = runner.runAsync(recordContext -> {
saveThreadContext.accept(runnerRunAsyncName);
return signal.thenCompose(vignore -> CompletableFuture.supplyAsync(() -> {
saveThreadContext.accept(supplyAsyncName);
if (attempts.getAndIncrement() == 0) {
throw new RecordCoreRetriableTransactionException("Retriable and lessener", new FDBException("not_committed", 1020));
} else {
return null;
}
}, recordContext.getExecutor()));
}).handle((result, exception) -> {
saveThreadContext.accept(handleName);
return exception;
});
signal.complete(null);
assertNull(task.join());
List<Map<String, String>> expected = ImmutableList.of(// it is known behavior that the first will be run in the current context
threadContextPlus(runnerRunAsyncName, 0, outer), threadContextPlus(supplyAsyncName, 0, restored), // the code that creates the future, should now have the correct MDC
threadContextPlus(runnerRunAsyncName, 1, restored), threadContextPlus(supplyAsyncName, 1, restored), // this should also have the correct MDC
threadContextPlus(handleName, 2, restored));
assertEquals(expected, threadContexts);
assertEquals(outer, ThreadContext.getContext());
} finally {
FDBDatabaseFactory.instance().setExecutor(oldExecutor);
}
}
use of com.apple.foundationdb.record.RecordCoreRetriableTransactionException in project fdb-record-layer by FoundationDB.
the class FDBDatabaseRunnerTest method runAsyncRetryToSuccess.
@Test
public void runAsyncRetryToSuccess() {
try (FDBDatabaseRunner runner = database.newRunner()) {
AtomicInteger count = new AtomicInteger(0);
String value = runner.runAsync(context -> {
if (count.getAndIncrement() == 0) {
throw new RecordCoreRetriableTransactionException("Have to try again!", new FDBException("not_committed", 1020));
} else {
return CompletableFuture.completedFuture("Success!");
}
}).join();
assertEquals("Success!", value);
assertEquals(2, count.get(), "Should only take one try");
count.set(0);
value = runner.runAsync(context -> {
if (count.getAndIncrement() == 0) {
throw new FDBException("not_committed", 1020);
} else {
return CompletableFuture.completedFuture("Success!");
}
}).join();
assertEquals("Success!", value);
assertEquals(2, count.get(), "Should only take one try");
count.set(0);
value = runner.runAsync(context -> {
if (count.getAndIncrement() == 0) {
throw new RecordCoreRetriableTransactionException("Something non-standard");
} else {
return CompletableFuture.completedFuture("Success!");
}
}).join();
assertEquals("Success!", value);
assertEquals(2, count.get(), "Should only take one try");
value = runner.runAsync(context -> CompletableFuture.completedFuture("Success!")).join();
assertEquals("Success!", value);
}
}
use of com.apple.foundationdb.record.RecordCoreRetriableTransactionException in project fdb-record-layer by FoundationDB.
the class FDBDatabaseRunnerTest method close.
@Test
public void close() throws Exception {
AtomicInteger iteration = new AtomicInteger(0);
CompletableFuture<Void> future;
try (FDBDatabaseRunner runner = database.newRunner()) {
runner.setMaxAttempts(Integer.MAX_VALUE);
runner.setInitialDelayMillis(100);
runner.setMaxDelayMillis(100);
future = runner.runAsync(context -> {
iteration.incrementAndGet();
throw new RecordCoreRetriableTransactionException("Have to try again!", new FDBException("not_committed", 1020));
});
}
int currentIteration = iteration.get();
assertThat("Should have run at least once", currentIteration, greaterThan(0));
try {
future.join();
fail("Should have stopped exceptionally");
} catch (Exception ex) {
if (!(ex instanceof FDBDatabaseRunner.RunnerClosed || (ex instanceof CompletionException && ex.getCause() instanceof FDBDatabaseRunner.RunnerClosed))) {
throw ex;
}
}
Thread.sleep(150);
assertEquals(currentIteration, iteration.get(), "Should have stopped running");
}
use of com.apple.foundationdb.record.RecordCoreRetriableTransactionException in project fdb-record-layer by FoundationDB.
the class FDBDatabaseRunnerTest method runRetryToSuccess.
@Test
public void runRetryToSuccess() {
try (FDBDatabaseRunner runner = database.newRunner()) {
AtomicInteger count = new AtomicInteger(0);
String value = runner.run(context -> {
if (count.getAndIncrement() == 0) {
throw new RecordCoreRetriableTransactionException("Have to try again!", new FDBException("not_committed", 1020));
} else {
return "Success!";
}
});
assertEquals("Success!", value);
assertEquals(2, count.get(), "Should only take one try");
count.set(0);
value = runner.run(context -> {
if (count.getAndIncrement() == 0) {
throw new FDBException("not_committed", 1020);
} else {
return "Success!";
}
});
assertEquals("Success!", value);
assertEquals(2, count.get(), "Should only take one try");
count.set(0);
value = runner.run(context -> {
if (count.getAndIncrement() == 0) {
throw new RecordCoreRetriableTransactionException("Something non-standard");
} else {
return "Success!";
}
});
assertEquals("Success!", value);
assertEquals(2, count.get(), "Should only take one try");
value = runner.run(context -> "Success!");
assertEquals("Success!", value);
}
}
use of com.apple.foundationdb.record.RecordCoreRetriableTransactionException in project fdb-record-layer by FoundationDB.
the class FDBDatabaseRunnerTest method runRetryNoSuccess.
@Test
public void runRetryNoSuccess() {
// The rest of the tests retry all of the way, so set guards to make sure they don't take forever.
try (FDBDatabaseRunner runner = database.newRunner()) {
runner.setMaxAttempts(5);
runner.setMaxDelayMillis(100);
runner.setInitialDelayMillis(5);
AtomicInteger iteration = new AtomicInteger(0);
try {
runner.run(context -> {
assertTrue(iteration.get() < runner.getMaxAttempts());
iteration.incrementAndGet();
throw new RecordCoreRetriableTransactionException("Have to try again!", new FDBException("not_committed", 1020));
});
fail("Did not catch retriable error that hit maximum retry limit");
} catch (RecordCoreException e) {
assertEquals("Have to try again!", e.getMessage());
assertNotNull(e.getCause());
assertTrue(e.getCause() instanceof FDBException);
assertEquals("not_committed", e.getCause().getMessage());
assertEquals(FDBError.NOT_COMMITTED.code(), ((FDBException) e.getCause()).getCode());
}
assertEquals(runner.getMaxAttempts(), iteration.get());
}
}
Aggregations