use of org.opendaylight.controller.cluster.access.concepts.RuntimeRequestException in project controller by opendaylight.
the class ClientTransactionCommitCohortTest method testOpFail.
/**
* Test operation failure. Invokes given operation, which initiates message to the backend.
* Received message is checked by expectFunction. Then replyFunction is invoked. One of the transactions in
* cohort receives failure response.
*
* @param operation operation
* @param expectFunction expected message check
* @param replyFunction response function
* @param <T> type
* @throws Exception unexpected exception
*/
private <T> void testOpFail(final Function<ClientTransactionCommitCohort, ListenableFuture<T>> operation, final Consumer<TransactionTester<RemoteProxyTransaction>> expectFunction, final Consumer<TransactionTester<RemoteProxyTransaction>> replyFunction) throws Exception {
final ListenableFuture<T> canCommit = operation.apply(cohort);
// reply success to all except last transaction
replySuccess(transactions.subList(0, transactions.size() - 1), expectFunction, replyFunction);
// reply fail to last transaction
final TransactionTester<RemoteProxyTransaction> last = transactions.get(transactions.size() - 1);
expectFunction.accept(last);
final RuntimeException e = new RuntimeException();
final RuntimeRequestException cause = new RuntimeRequestException("fail", e);
last.replyFailure(cause);
// check future fail
final ExecutionException exception = assertOperationThrowsException(() -> getWithTimeout(canCommit), ExecutionException.class);
Assert.assertEquals(e, exception.getCause());
}
use of org.opendaylight.controller.cluster.access.concepts.RuntimeRequestException in project controller by opendaylight.
the class AbstractClientConnectionTest method testPoison.
@Test
public void testPoison() throws Exception {
final Consumer<Response<?, ?>> callback = mock(Consumer.class);
final Request<?, ?> request = createRequest(replyToProbe.ref());
final ConnectionEntry entry = new ConnectionEntry(request, callback, 0L);
connection.enqueueEntry(entry, 0L);
connection.poison(new RuntimeRequestException("fail", new RuntimeException("fail")));
verify(callback, timeout(1000)).accept(isA(TransactionFailure.class));
}
use of org.opendaylight.controller.cluster.access.concepts.RuntimeRequestException in project controller by opendaylight.
the class AbstractClientConnection method runTimer.
/**
* Check this queue for timeout and initiate reconnection if that happened. If the queue has not made progress
* in {@link #DEFAULT_NO_PROGRESS_TIMEOUT_NANOS} nanoseconds, it will be aborted.
*
* @param current Current behavior
* @return Next behavior to use
*/
@VisibleForTesting
final ClientActorBehavior<T> runTimer(final ClientActorBehavior<T> current) {
final Optional<Long> delay;
lock.lock();
try {
haveTimer = false;
final long now = currentTime();
LOG.debug("{}: running timer on {}", context.persistenceId(), this);
// The following line is only reliable when queue is not forwarding, but such state should not last long.
// FIXME: BUG-8422: this may not be accurate w.r.t. replayed entries
final long ticksSinceProgress = queue.ticksStalling(now);
if (ticksSinceProgress >= context.config().getNoProgressTimeout()) {
LOG.error("Queue {} has not seen progress in {} seconds, failing all requests", this, TimeUnit.NANOSECONDS.toSeconds(ticksSinceProgress));
lockedPoison(new NoProgressException(ticksSinceProgress));
current.removeConnection(this);
return current;
}
// Requests are always scheduled in sequence, hence checking for timeout is relatively straightforward.
// Note we use also inquire about the delay, so we can re-schedule if needed, hence the unusual tri-state
// return convention.
delay = lockedCheckTimeout(now);
if (delay == null) {
// We have timed out. There is no point in scheduling a timer
LOG.debug("{}: connection {} timed out", context.persistenceId(), this);
return lockedReconnect(current, new RuntimeRequestException("Backend connection timed out", new TimeoutException()));
}
if (delay.isPresent()) {
// If there is new delay, schedule a timer
scheduleTimer(delay.get());
} else {
LOG.debug("{}: not scheduling timeout on {}", context.persistenceId(), this);
}
} finally {
lock.unlock();
}
return current;
}
use of org.opendaylight.controller.cluster.access.concepts.RuntimeRequestException in project controller by opendaylight.
the class FrontendReadWriteTransaction method handleTransactionAbort.
private TransactionAbortSuccess handleTransactionAbort(final long sequence, final RequestEnvelope envelope, final long now) {
if (state instanceof Open) {
final ReadWriteShardDataTreeTransaction openTransaction = checkOpen();
startAbort();
openTransaction.abort(() -> {
recordAndSendSuccess(envelope, now, new TransactionAbortSuccess(getIdentifier(), sequence));
finishAbort();
});
return null;
}
if (ABORTING.equals(state)) {
LOG.debug("{}: Transaction {} already aborting", persistenceId(), getIdentifier());
return null;
}
if (ABORTED.equals(state)) {
// We should have recorded the reply
LOG.warn("{}: Transaction {} already aborted", persistenceId(), getIdentifier());
return new TransactionAbortSuccess(getIdentifier(), sequence);
}
final Ready ready = checkReady();
startAbort();
ready.readyCohort.abort(new FutureCallback<Void>() {
@Override
public void onSuccess(final Void result) {
recordAndSendSuccess(envelope, now, new TransactionAbortSuccess(getIdentifier(), sequence));
finishAbort();
}
@Override
public void onFailure(final Throwable failure) {
recordAndSendFailure(envelope, now, new RuntimeRequestException("Abort failed", failure));
LOG.warn("{}: Transaction {} abort failed", persistenceId(), getIdentifier(), failure);
finishAbort();
}
});
return null;
}
use of org.opendaylight.controller.cluster.access.concepts.RuntimeRequestException in project controller by opendaylight.
the class FrontendTransaction method handleRequest.
// Request order has already been checked by caller and replaySequence()
@SuppressWarnings("checkstyle:IllegalCatch")
@Nullable
final TransactionSuccess<?> handleRequest(final TransactionRequest<?> request, final RequestEnvelope envelope, final long now) throws RequestException {
if (request instanceof IncrementTransactionSequenceRequest) {
final IncrementTransactionSequenceRequest incr = (IncrementTransactionSequenceRequest) request;
expectedSequence += incr.getIncrement();
return recordSuccess(incr.getSequence(), new IncrementTransactionSequenceSuccess(incr.getTarget(), incr.getSequence()));
}
if (previousFailure != null) {
LOG.debug("{}: Rejecting request {} due to previous failure", persistenceId(), request, previousFailure);
throw previousFailure;
}
try {
return doHandleRequest(request, envelope, now);
} catch (RuntimeException e) {
/*
* The request failed to process, we should not attempt to ever
* apply it again. Furthermore we cannot accept any further requests
* from this connection, simply because the transaction state is
* undefined.
*/
LOG.debug("{}: Request {} failed to process", persistenceId(), request, e);
previousFailure = new RuntimeRequestException("Request " + request + " failed to process", e);
throw previousFailure;
}
}
Aggregations