@Override public void enqueue(Callback callback) { ListenableFuture<Limiter.Listener> limiterListener = limiter.acquire(); request().tag(ConcurrencyLimiterListener.class).limiterListener().setFuture(limiterListener); Futures.addCallback(limiterListener, new FutureCallback<Limiter.Listener>() { @Override public void onSuccess(Limiter.Listener listener) { enqueueInternal(callback); } @Override public void onFailure(Throwable throwable) { callback.onFailure( RemotingOkHttpCall.this, new IOException(new AssertionError("This should never happen, since it implies " + "we failed when using the concurrency limiter", throwable))); } }, MoreExecutors.directExecutor()); }
@Override public void enqueue(Callback callback) { ListenableFuture<Limiter.Listener> limiterListener = limiter.acquire(); request().tag(ConcurrencyLimiterListener.class).limiterListener().setFuture(limiterListener); Futures.addCallback(limiterListener, new FutureCallback<Limiter.Listener>() { @Override public void onSuccess(Limiter.Listener listener) { enqueueInternal(callback); } @Override public void onFailure(Throwable throwable) { callback.onFailure( RemotingOkHttpCall.this, new IOException(new AssertionError("This should never happen, since it implies " + "we failed when using the concurrency limiter", throwable))); } }, MoreExecutors.directExecutor()); }
private Thread exhaust() { Thread thread = new Thread(() -> { while (true) { try { limiters.acquireLimiterInternal(KEY).acquire().get(); } catch (ExecutionException | InterruptedException e) { throw new RuntimeException(e); } } }); thread.start(); // wait until the other thread blocks while (!thread.getState().equals(Thread.State.WAITING)) { Thread.yield(); } return thread; } }
@Override public void run() { for (int i = 0; i < REQUESTS_PER_THREAD; ) { Limiter.Listener listener = Futures.getUnchecked(limiters.acquireLimiterInternal("").acquire()); boolean gotRateLimited = !rateLimiter.tryAcquire(100, TimeUnit.MILLISECONDS); if (!gotRateLimited) { meter.mark(); sleep(successDuration.toMillis()); listener.onSuccess(); avgRetries.update(numRetries); numRetries = 0; backoff = null; i++; } else { initializeBackoff(); Optional<Duration> sleep = backoff.nextBackoff(); numRetries++; if (!sleep.isPresent()) { listener.onIgnore(); throw new RuntimeException("Failed on request " + i); } else { sleep(1); listener.onDropped(); sleep(sleep.get().toMillis()); } } } }
@Test public void testTimeout() { Instant start = Instant.now(); Thread exhauster = exhaust(); Futures.getUnchecked(limiters.acquireLimiterInternal(KEY).acquire()); Instant end = Instant.now(); exhauster.interrupt(); assertThat(Duration.between(start, end)).isGreaterThanOrEqualTo(TIMEOUT); }