public ListenableFuture<Object> invoke(Optional<String> addressSelectionContext, Map<String, String> headers, List<Object> parameters) { if (!headerParameters.isEmpty()) { headers = new LinkedHashMap<>(headers); for (Entry<Integer, ThriftHeaderParameter> entry : headerParameters.entrySet()) { String headerValue = (String) parameters.get(entry.getKey()); if (headerValue != null) { headers.put(entry.getValue().getName(), headerValue); } } ImmutableList.Builder<Object> newParameters = ImmutableList.builder(); for (int index = 0; index < parameters.size(); index++) { if (!headerParameters.containsKey(index)) { newParameters.add(parameters.get(index)); } } parameters = newParameters.build(); } return createDriftMethodInvocation(invoker, metadata, headers, parameters, retryPolicy, addressSelector, addressSelectionContext, stat, Ticker.systemTicker()); } }
static <A extends Address> DriftMethodInvocation<A> createDriftMethodInvocation( MethodInvoker invoker, MethodMetadata metadata, Map<String, String> headers, List<Object> parameters, RetryPolicy retryPolicy, AddressSelector<A> addressSelector, Optional<String> addressSelectionContext, MethodInvocationStat stat, Ticker ticker) { DriftMethodInvocation<A> invocation = new DriftMethodInvocation<>( invoker, metadata, headers, parameters, retryPolicy, addressSelector, addressSelectionContext, stat, ticker); // invocation can not be started from constructor, because it may start threads that can call back into the unpublished object invocation.nextAttempt(true); return invocation; }
if (isCancelled()) { return; fail("No hosts available"); return; invoke(address.get()); return; invoke(address.get()); return; schedule(connectDelay, () -> invoke(address.get())); unexpectedError(t);
private DriftMethodInvocation( MethodInvoker invoker, MethodMetadata metadata, Map<String, String> headers, List<Object> parameters, RetryPolicy retryPolicy, AddressSelector<A> addressSelector, Optional<String> addressSelectionContext, MethodInvocationStat stat, Ticker ticker) { this.invoker = requireNonNull(invoker, "methodHandler is null"); this.metadata = requireNonNull(metadata, "metadata is null"); this.headers = requireNonNull(headers, "headers is null"); this.parameters = requireNonNull(parameters, "parameters is null"); this.retryPolicy = requireNonNull(retryPolicy, "retryPolicy is null"); this.addressSelector = requireNonNull(addressSelector, "addressSelector is null"); this.addressSelectionContext = requireNonNull(addressSelectionContext, "addressSelectionContext is null"); this.stat = requireNonNull(stat, "stat is null"); this.ticker = requireNonNull(ticker, "ticker is null"); this.startTime = ticker.read(); // if this invocation is canceled, cancel the tasks super.addListener(() -> { if (super.isCancelled()) { onCancel(wasInterrupted()); } }, directExecutor()); }
fail("Non-retryable exception"); return; fail(format("Max retry attempts (%s) exceeded", retryPolicy.getMaxRetries())); return; fail(format("Max retry time (%s) exceeded", retryPolicy.getMaxRetryTime())); return; nextAttempt(false); return; overloadedRejects, throwable.getMessage()); schedule(backoffDelay, () -> nextAttempt(true)); unexpectedError(t);
@Test(timeOut = 60000) public void testFirstTrySuccess() throws Exception { TestingMethodInvocationStat stat = new TestingMethodInvocationStat(); DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation(RetryPolicy.NO_RETRY_POLICY, stat, () -> immediateFuture(SUCCESS)); assertEquals(methodInvocation.get(), SUCCESS); stat.assertSuccess(0); }
private static void testPropagateCancel(int expectedRetries, boolean interrupt) throws Exception { RetryPolicy retryPolicy = new RetryPolicy(new DriftClientConfig().setMaxRetries(expectedRetries + 10), new TestingExceptionClassifier()); TestingMethodInvocationStat stat = new TestingMethodInvocationStat(); AtomicInteger attempts = new AtomicInteger(); TestFuture future = new TestFuture(); CountDownLatch settableFutureFetched = new CountDownLatch(1); DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation( retryPolicy, stat, () -> { attempts.getAndIncrement(); if (attempts.get() > expectedRetries) { settableFutureFetched.countDown(); return future; } return immediateFailedFuture(createClassifiedException(true, NORMAL)); }); settableFutureFetched.await(); methodInvocation.cancel(interrupt); assertTrue(future.isCancelled()); assertEquals(future.checkWasInterrupted(), interrupt); assertEquals(attempts.get(), expectedRetries + 1); }
fail("Non-retryable exception"); return; fail(format("Max retry attempts (%s) exceeded", retryPolicy.getMaxRetries())); return; fail(format("Max retry time (%s) exceeded", retryPolicy.getMaxRetryTime())); return; nextAttempt(false); return; overloadedRejects, throwable.getMessage()); schedule(backoffDelay, () -> nextAttempt(true)); unexpectedError(t);
private static void testExceptionFromInvokerInvoke(int expectedRetries) throws Exception { RetryPolicy retryPolicy = new RetryPolicy(new DriftClientConfig().setMaxRetries(expectedRetries + 10), new TestingExceptionClassifier()); TestingMethodInvocationStat stat = new TestingMethodInvocationStat(); AtomicInteger attempts = new AtomicInteger(); DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation( retryPolicy, stat, () -> { attempts.getAndIncrement(); if (attempts.get() > expectedRetries) { throw UNEXPECTED_EXCEPTION; } return immediateFailedFuture(createClassifiedException(true, NORMAL)); }); try { methodInvocation.get(); fail("Expected exception"); } catch (ExecutionException e) { assertEquals(attempts.get(), expectedRetries + 1); assertUnexpectedException(e.getCause()); } }
private DriftMethodInvocation( MethodInvoker invoker, MethodMetadata metadata, Map<String, String> headers, List<Object> parameters, RetryPolicy retryPolicy, AddressSelector<A> addressSelector, Optional<String> addressSelectionContext, MethodInvocationStat stat, Ticker ticker) { this.invoker = requireNonNull(invoker, "methodHandler is null"); this.metadata = requireNonNull(metadata, "metadata is null"); this.headers = requireNonNull(headers, "headers is null"); this.parameters = requireNonNull(parameters, "parameters is null"); this.retryPolicy = requireNonNull(retryPolicy, "retryPolicy is null"); this.addressSelector = requireNonNull(addressSelector, "addressSelector is null"); this.addressSelectionContext = requireNonNull(addressSelectionContext, "addressSelectionContext is null"); this.stat = requireNonNull(stat, "stat is null"); this.ticker = requireNonNull(ticker, "ticker is null"); this.startTime = ticker.read(); // if this invocation is canceled, cancel the tasks super.addListener(() -> { if (super.isCancelled()) { onCancel(wasInterrupted()); } }, directExecutor()); }
if (isCancelled()) { return; fail("No hosts available"); return; invoke(address.get()); return; invoke(address.get()); return; schedule(connectDelay, () -> invoke(address.get())); unexpectedError(t);
@Test(timeOut = 60000) public void testMaxRetries() throws Exception { int maxRetries = 5; RetryPolicy retryPolicy = new RetryPolicy(new DriftClientConfig().setMaxRetries(maxRetries), new TestingExceptionClassifier()); TestingMethodInvocationStat stat = new TestingMethodInvocationStat(); AtomicInteger attempts = new AtomicInteger(); DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation(retryPolicy, stat, () -> { attempts.getAndIncrement(); return immediateFailedFuture(createClassifiedException(true, NORMAL)); }); try { methodInvocation.get(); fail("Expected exception"); } catch (ExecutionException e) { assertEquals(attempts.get(), maxRetries + 1); assertClassifiedException(e.getCause(), new ExceptionClassification(Optional.of(true), NORMAL), maxRetries); } stat.assertFailure(maxRetries); }
public ListenableFuture<Object> invoke(Optional<String> addressSelectionContext, Map<String, String> headers, List<Object> parameters) { if (!headerParameters.isEmpty()) { headers = new LinkedHashMap<>(headers); for (Entry<Integer, ThriftHeaderParameter> entry : headerParameters.entrySet()) { String headerValue = (String) parameters.get(entry.getKey()); if (headerValue != null) { headers.put(entry.getValue().getName(), headerValue); } } ImmutableList.Builder<Object> newParameters = ImmutableList.builder(); for (int index = 0; index < parameters.size(); index++) { if (!headerParameters.containsKey(index)) { newParameters.add(parameters.get(index)); } } parameters = newParameters.build(); } return createDriftMethodInvocation(invoker, metadata, headers, parameters, retryPolicy, addressSelector, addressSelectionContext, stat, Ticker.systemTicker()); } }
static <A extends Address> DriftMethodInvocation<A> createDriftMethodInvocation( MethodInvoker invoker, MethodMetadata metadata, Map<String, String> headers, List<Object> parameters, RetryPolicy retryPolicy, AddressSelector<A> addressSelector, Optional<String> addressSelectionContext, MethodInvocationStat stat, Ticker ticker) { DriftMethodInvocation<A> invocation = new DriftMethodInvocation<>( invoker, metadata, headers, parameters, retryPolicy, addressSelector, addressSelectionContext, stat, ticker); // invocation can not be started from constructor, because it may start threads that can call back into the unpublished object invocation.nextAttempt(true); return invocation; }
methodInvocation.get(); fail("Expected exception");
private static DriftMethodInvocation<?> createDriftMethodInvocation( RetryPolicy retryPolicy, TestingMethodInvocationStat stat, MockMethodInvoker invoker, AddressSelector<?> addressSelector, Ticker ticker) { return DriftMethodInvocation.createDriftMethodInvocation( invoker, METHOD_METADATA, ImmutableMap.of(), ImmutableList.of(), retryPolicy, addressSelector, Optional.empty(), stat, ticker); }
@Test(timeOut = 60000) public void testBasicRetriesToNoHosts() throws Exception { RetryPolicy retryPolicy = new RetryPolicy(new DriftClientConfig().setMaxRetries(10), new TestingExceptionClassifier()); TestingMethodInvocationStat stat = new TestingMethodInvocationStat(); AtomicInteger attempts = new AtomicInteger(); int expectedRetries = 3; DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation( retryPolicy, stat, new MockMethodInvoker(() -> { attempts.getAndIncrement(); return immediateFailedFuture(createClassifiedException(true, NORMAL)); }), new TestingAddressSelector(expectedRetries + 1), systemTicker()); try { methodInvocation.get(); fail("Expected exception"); } catch (ExecutionException e) { assertEquals(attempts.get(), expectedRetries + 1); assertClassifiedException(e.getCause(), new ExceptionClassification(Optional.of(true), NORMAL), expectedRetries); } stat.assertFailure(expectedRetries); }
methodInvocation.get(); fail("Expected exception");
methodInvocation.get(); fail("Expected exception");
methodInvocation.get(); fail("Expected exception");