use of com.twitter.common.thrift.TResourceExhaustedException in project commons by twitter.
the class RetryingCaller method call.
@Override
public Object call(final Method method, final Object[] args, @Nullable final AsyncMethodCallback callback, @Nullable final Amount<Long, Time> connectTimeoutOverride) throws Throwable {
final AtomicLong retryCounter = stats.get(method);
final AtomicInteger attempts = new AtomicInteger();
final List<Throwable> exceptions = Lists.newArrayList();
final ResultCapture capture = new ResultCapture() {
@Override
public void success() {
// No-op.
}
@Override
public boolean fail(Throwable t) {
if (!isRetryable(t)) {
if (debug) {
LOG.warning(String.format("Call failed with un-retryable exception of [%s]: %s, previous exceptions: %s", t.getClass().getName(), t.getMessage(), combineStackTraces(exceptions)));
}
return true;
} else if (attempts.get() >= retries) {
exceptions.add(t);
if (debug) {
LOG.warning(String.format("Retried %d times, last error: %s, exceptions: %s", attempts.get(), t, combineStackTraces(exceptions)));
}
return true;
} else {
exceptions.add(t);
if (isAsync() && attempts.incrementAndGet() <= retries) {
try {
retryCounter.incrementAndGet();
// override connect timeout in ThriftCaller to prevent blocking for a connection
// for async retries (since this is within the callback in the selector thread)
invoke(method, args, callback, this, NONBLOCKING_TIMEOUT);
} catch (Throwable throwable) {
return fail(throwable);
}
}
return false;
}
}
};
boolean continueLoop;
do {
try {
// If this is an async call, the looping will be handled within the capture.
return invoke(method, args, callback, capture, connectTimeoutOverride);
} catch (Throwable t) {
if (!isRetryable(t)) {
Throwable propagated = t;
if (!exceptions.isEmpty() && (t instanceof TResourceExhaustedException)) {
// If we've been trucking along through retries that have had remote call failures
// and we suddenly can't immediately get a connection on the next retry, throw the
// previous remote call failure - the idea here is that the remote call failure is
// more interesting than a transient inability to get an immediate connection.
propagated = exceptions.remove(exceptions.size() - 1);
}
if (isAsync()) {
callback.onError(propagated);
} else {
throw propagated;
}
}
}
continueLoop = !isAsync() && attempts.incrementAndGet() <= retries;
if (continueLoop)
retryCounter.incrementAndGet();
} while (continueLoop);
Throwable lastRetriedException = Iterables.getLast(exceptions);
if (debug) {
if (!exceptions.isEmpty()) {
LOG.warning(String.format("Retried %d times, last error: %s, previous exceptions: %s", attempts.get(), lastRetriedException, combineStackTraces(exceptions)));
} else {
LOG.warning(String.format("Retried 1 time, last error: %s", lastRetriedException));
}
}
if (!isAsync())
throw lastRetriedException;
return null;
}
use of com.twitter.common.thrift.TResourceExhaustedException in project commons by twitter.
the class StatTrackingCaller method call.
@Override
public Object call(Method method, Object[] args, @Nullable AsyncMethodCallback callback, @Nullable Amount<Long, Time> connectTimeoutOverride) throws Throwable {
final RequestTimer requestStats = stats.get(method);
final long startTime = System.nanoTime();
ResultCapture capture = new ResultCapture() {
@Override
public void success() {
requestStats.requestComplete(TimeUnit.NANOSECONDS.toMicros(System.nanoTime() - startTime));
}
@Override
public boolean fail(Throwable t) {
// backoff mechanism - consider how to plumb something similar.
if (t instanceof TTimeoutException || t instanceof TimeoutException) {
requestStats.incTimeouts();
return true;
}
// it stands.
if (!(t instanceof TResourceExhaustedException)) {
requestStats.incReconnects();
}
// TODO(John Sirois): provide more detailed stats: track counts for distinct exceptions types,
// track retries-per-method, etc...
requestStats.incErrors();
return true;
}
};
return invoke(method, args, callback, capture, connectTimeoutOverride);
}
use of com.twitter.common.thrift.TResourceExhaustedException in project commons by twitter.
the class ServerSetImplTest method testThriftWithServerSet.
//TODO(Jake Mannix) move this test method to ServerSetConnectionPoolTest, which should be renamed
// to DynamicBackendConnectionPoolTest, and refactor assertChangeFired* methods to be used both
// here and there
@Test
public void testThriftWithServerSet() throws Exception {
final AtomicReference<Socket> clientConnection = new AtomicReference<Socket>();
final CountDownLatch connected = new CountDownLatch(1);
final ServerSocket server = new ServerSocket(0);
Thread service = new Thread(new Runnable() {
@Override
public void run() {
try {
clientConnection.set(server.accept());
} catch (IOException e) {
LOG.log(Level.WARNING, "Problem accepting a connection to thrift server", e);
} finally {
connected.countDown();
}
}
});
service.setDaemon(true);
service.start();
ServerSetImpl serverSetImpl = new ServerSetImpl(createZkClient(), SERVICE);
serverSetImpl.watch(serverSetMonitor);
assertChangeFiredEmpty();
InetSocketAddress localSocket = new InetSocketAddress(server.getLocalPort());
serverSetImpl.join(localSocket, Maps.<String, InetSocketAddress>newHashMap());
assertChangeFired(ImmutableMap.<InetSocketAddress, Status>of(localSocket, Status.ALIVE));
Service.Iface svc = createThriftClient(serverSetImpl);
try {
String value = svc.getString();
LOG.info("Got value: " + value + " from server");
assertEquals(Service.Iface.DONE, value);
} catch (TResourceExhaustedException e) {
fail("ServerSet is not empty, should not throw exception here");
} finally {
connected.await();
server.close();
}
}
Aggregations