use of com.github.rholder.retry.Retryer in project graylog2-server by Graylog2.
the class LocalKafkaMessageQueueWriter method write.
@Override
public void write(List<RawMessageEvent> entries) throws MessageQueueException {
final AtomicLong msgBytes = new AtomicLong(0);
final List<Journal.Entry> journalEntries = entries.stream().filter(Objects::nonNull).map(e -> new Journal.Entry(e.getMessageIdBytes(), e.getEncodedRawMessage())).peek(e -> msgBytes.addAndGet(e.getMessageBytes().length)).collect(Collectors.toList());
try {
writeToJournal(journalEntries);
} catch (Exception e) {
LOG.error("Unable to write to journal - retrying", e);
// Use retryer with exponential back-off to avoid spamming the logs.
try {
writeRetryer.call(() -> {
writeToJournal(journalEntries);
return null;
});
} catch (ExecutionException | RetryException ex) {
throw new MessageQueueException("Retryer exception", ex);
}
}
metrics.writtenMessages().mark(journalEntries.size());
metrics.writtenBytes().mark(msgBytes.get());
}
use of com.github.rholder.retry.Retryer in project gerrit by GerritCodeReview.
the class RepoSequenceTest method idCanBeRetrievedFromOtherThreadWhileWaitingToRetry.
@Test
public void idCanBeRetrievedFromOtherThreadWhileWaitingToRetry() throws Exception {
// Seed existing ref value.
writeBlob("id", "1");
// Let the first update of the sequence fail with LOCK_FAILURE, so that the update is retried.
CountDownLatch lockFailure = new CountDownLatch(1);
CountDownLatch parallelSuccessfulSequenceGeneration = new CountDownLatch(1);
AtomicBoolean doneBgUpdate = new AtomicBoolean(false);
Runnable bgUpdate = () -> {
if (!doneBgUpdate.getAndSet(true)) {
writeBlob("id", "1234");
}
};
BlockStrategy blockStrategy = t -> {
// Keep blocking until we verified that another thread can retrieve a sequence number
// while we are blocking here.
lockFailure.countDown();
parallelSuccessfulSequenceGeneration.await();
};
// Use batch size = 1 to make each call go to NoteDb.
RepoSequence s = newSequence("id", 1, 1, bgUpdate, RepoSequence.retryerBuilder().withBlockStrategy(blockStrategy).build());
assertThat(doneBgUpdate.get()).isFalse();
// Start a thread to get a sequence number. This thread needs to update the sequence in NoteDb,
// but due to the background update (see bgUpdate) the first attempt to update NoteDb fails
// with LOCK_FAILURE. RepoSequence uses a retryer to retry the NoteDb update on LOCK_FAILURE,
// but our block strategy ensures that this retry only happens after isBlocking was set to
// false.
Future<?> future = Executors.newFixedThreadPool(1).submit(() -> {
// The background update sets the next available sequence number to 1234. Then the
// test thread retrieves one sequence number, so that the next available sequence
// number for this thread is 1235.
expect.that(s.next()).isEqualTo(1235);
});
// Wait until the LOCK_FAILURE has happened and the block strategy was entered.
lockFailure.await();
// Verify that the background update was done now.
assertThat(doneBgUpdate.get()).isTrue();
// Verify that we can retrieve a sequence number while the other thread is blocked. If the
// s.next() call hangs it means that the RepoSequence.counterLock was not released before the
// background thread started to block for retry. In this case the test would time out.
assertThat(s.next()).isEqualTo(1234);
// Stop blocking the retry of the background thread (and verify that it was still blocked).
parallelSuccessfulSequenceGeneration.countDown();
// Wait until the background thread is done.
future.get();
// Two successful acquire calls (because batch size == 1).
assertThat(s.acquireCount).isEqualTo(2);
}
Aggregations