use of com.linkedin.r2.transport.http.client.SmoothRateLimiter in project rest.li by linkedin.
the class TestRampUpRateLimiter method testRampUp.
@Test(dataProvider = "targetRamp", timeOut = TEST_TIMEOUT * 1000)
public void testRampUp(int targetPermitsPerPeriod, float rampUp) {
boolean useRampUpMethod = false;
for (int k = 0; k < 2; k++, useRampUpMethod = true) {
_queue.clear();
ClockedExecutor clockedExecutor = new ClockedExecutor();
RampUpRateLimiter rateLimiter = new RampUpRateLimiterImpl(new SmoothRateLimiter(clockedExecutor, clockedExecutor, clockedExecutor, _queue, Integer.MAX_VALUE, SmoothRateLimiter.BufferOverflowMode.DROP, RATE_LIMITER_NAME_TEST), clockedExecutor);
rateLimiter.setRate(0, 1, MINIMUM_BURST, rampUp);
rateLimiter.setRate(targetPermitsPerPeriod, ONE_SECOND_PERIOD, MINIMUM_BURST, rampUp);
if (useRampUpMethod) {
// issue close to 0 permits to have a successful ramp up afterwards
rateLimiter.setRate(0, 1, MINIMUM_BURST, rampUp);
rateLimiter.setRate(targetPermitsPerPeriod, ONE_SECOND_PERIOD, MINIMUM_BURST, rampUp);
}
AtomicInteger time = new AtomicInteger(0);
AtomicInteger count = new AtomicInteger(0);
List<Integer> completionsPerSecond = new ArrayList<>();
int secondsToReachTargetState = (int) Math.ceil(targetPermitsPerPeriod / rampUp);
IntStream.range(0, (int) (rampUp * secondsToReachTargetState * (secondsToReachTargetState + 1))).forEach(i -> {
rateLimiter.submit(new Callback<None>() {
@Override
public void onError(Throwable e) {
throw new RuntimeException(e);
}
@Override
public void onSuccess(None result) {
// counting how many tasks per second we are receiving.
if (clockedExecutor.getCurrentTimeMillis() - time.get() >= ONE_SECOND_PERIOD) {
time.set(((int) (clockedExecutor.getCurrentTimeMillis() / 1000) * 1000));
completionsPerSecond.add(count.get());
count.set(1);
} else {
count.incrementAndGet();
}
}
});
});
// run the clock only for the exact amount of time that is necessary to reach the stable state
clockedExecutor.runFor((long) ((secondsToReachTargetState + 2) * 1000));
long countAboveMaxTarget = 0;
long countAtTarget = 0;
long countBelowTarget = 0;
for (Integer i : completionsPerSecond) {
if (i > targetPermitsPerPeriod)
countAboveMaxTarget++;
if (i == targetPermitsPerPeriod)
countAtTarget++;
if (i < targetPermitsPerPeriod)
countBelowTarget++;
}
assertEquals(countAboveMaxTarget, 0, "It should never go above the target QPS");
assertTrue(countAtTarget > 0, "There should be at least one at the target QPS since it should reach the stable state after a while");
long actualStepsToTarget = (countBelowTarget + 1) + // we want to account for the first seconds in which no task will return if the rampUp<1
(rampUp < 1 ? (long) (1 / rampUp) - 1 : 0);
// using countABelowTarget+1, because the one from the last number to the target is never counted
assertTrue(actualStepsToTarget >= secondsToReachTargetState * 0.9 && actualStepsToTarget <= Math.ceil(secondsToReachTargetState * 1.1), "There should be at least " + secondsToReachTargetState * 0.9 + " steps to get to the target and no more than " + Math.ceil(secondsToReachTargetState * 1.1) + ". Found: " + actualStepsToTarget + ".");
}
}
use of com.linkedin.r2.transport.http.client.SmoothRateLimiter in project rest.li by linkedin.
the class TestSmoothRateLimiter method testSubmitExceedsMaxBuffered.
@Test(timeOut = TEST_TIMEOUT)
public void testSubmitExceedsMaxBuffered() {
SmoothRateLimiter rateLimiter = new SmoothRateLimiter(_scheduledExecutorService, _executor, _clock, _queue, 0, SmoothRateLimiter.BufferOverflowMode.DROP, RATE_LIMITER_NAME_TEST);
rateLimiter.setRate(ONE_PERMIT_PER_PERIOD, ONE_SECOND_PERIOD, UNLIMITED_BURST);
FutureCallback<None> callback = new FutureCallback<>();
try {
rateLimiter.submit(callback);
} catch (RejectedExecutionException e) {
Assert.assertFalse("The tasks should have been rejected and not run", callback.isDone());
// success, the exception has been thrown as expected!
return;
}
Assert.fail("It should have thrown a RejectedExecutionException");
}
use of com.linkedin.r2.transport.http.client.SmoothRateLimiter in project rest.li by linkedin.
the class TestRampUpRateLimiter method testRampDownImmediately.
@Test(timeOut = TEST_TIMEOUT)
public void testRampDownImmediately() {
ClockedExecutor clockedExecutor = new ClockedExecutor();
RampUpRateLimiter rateLimiter = new RampUpRateLimiterImpl(new SmoothRateLimiter(clockedExecutor, clockedExecutor, clockedExecutor, _queue, Integer.MAX_VALUE, SmoothRateLimiter.BufferOverflowMode.DROP, RATE_LIMITER_NAME_TEST), clockedExecutor);
rateLimiter.setRate(1000d, ONE_SECOND_PERIOD, MINIMUM_BURST);
List<FutureCallback<None>> callbacks = new ArrayList<>();
IntStream.range(0, 1002).forEach(i -> {
FutureCallback<None> callback = new FutureCallback<>();
rateLimiter.submit(callback);
callbacks.add(callback);
});
// -1 because if it passes a full second, the new batch of permits will be issued
clockedExecutor.runFor(ONE_SECOND_PERIOD - 1);
IntStream.range(0, 1000).forEach(i -> assertTrue(callbacks.get(i).isDone()));
IntStream.range(1000, 1002).forEach(i -> assertFalse(callbacks.get(i).isDone(), i + " should not have been executed"));
rateLimiter.setRate(1, ONE_SECOND_PERIOD, 1, Integer.MAX_VALUE);
clockedExecutor.runFor(ONE_SECOND_PERIOD);
IntStream.range(1000, 1001).forEach(i -> assertTrue(callbacks.get(i).isDone()));
IntStream.range(1001, 1002).forEach(i -> assertFalse(callbacks.get(i).isDone(), i + " should not have been executed"));
clockedExecutor.runFor(ONE_SECOND_PERIOD);
IntStream.range(1001, 1002).forEach(i -> assertTrue(callbacks.get(i).isDone()));
}
use of com.linkedin.r2.transport.http.client.SmoothRateLimiter in project rest.li by linkedin.
the class TestSmoothRateLimiter method testSubmitExceedsMaxBufferedButNoReject.
@Test(timeOut = TEST_TIMEOUT)
public void testSubmitExceedsMaxBufferedButNoReject() throws InterruptedException, ExecutionException, TimeoutException {
SmoothRateLimiter rateLimiter = new SmoothRateLimiter(_scheduledExecutorService, _executor, _clock, _queue, 0, SmoothRateLimiter.BufferOverflowMode.SCHEDULE_WITH_WARNING, RATE_LIMITER_NAME_TEST);
rateLimiter.setRate(ONE_PERMIT_PER_PERIOD, ONE_SECOND_PERIOD, UNLIMITED_BURST);
int numberOfTasks = 100;
FutureCallback<None> callback = new FutureCallback<>();
Callback<None> callbacks = new MultiCallback(callback, numberOfTasks);
for (int i = 0; i < numberOfTasks; i++) {
try {
rateLimiter.submit(callbacks);
} catch (RejectedExecutionException e) {
Assert.fail("It should have just run a task and not throw a RejectedExecutionException");
}
}
callback.get(5, TimeUnit.SECONDS);
Assert.assertTrue("The tasks should run", callback.isDone());
}
Aggregations