/** * Returns async limiter that users can subscribe to be notified when limit permit has been granted. Caller must * notify the listener to release the permit. */ ConcurrencyLimiter acquireLimiter(Request request) { return acquireLimiterInternal(limiterKey(request)); }
/** * Returns async limiter that users can subscribe to be notified when limit permit has been granted. Caller must * notify the listener to release the permit. */ ConcurrencyLimiter acquireLimiter(Request request) { return acquireLimiterInternal(limiterKey(request)); }
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; } }
@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); }
@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()); } } } }