use of com.linkedin.r2.util.Timeout in project rest.li by linkedin.
the class BaseTestSmoothRateLimiter method testCancelAll.
@Test(timeOut = TEST_TIMEOUT)
public void testCancelAll() throws Exception {
SettableClock clock = new SettableClock();
AsyncRateLimiter rateLimiter = getRateLimiter(_scheduledExecutorService, _executor, clock);
rateLimiter.setRate(ONE_PERMIT_PER_PERIOD, ONE_MILLISECOND_PERIOD, UNLIMITED_BURST);
List<FutureCallback<None>> callbacks = new ArrayList<>();
IntStream.range(0, 5).forEach(i -> {
FutureCallback<None> callback = new FutureCallback<>();
rateLimiter.submit(callback);
callbacks.add(callback);
});
// We have one permit to begin with so the first task should run immediate and left with four pending
callbacks.get(0).get();
IntStream.range(0, 1).forEach(i -> assertTrue(callbacks.get(i).isDone()));
IntStream.range(1, 5).forEach(i -> assertFalse(callbacks.get(i).isDone()));
// We cancel all pending callbacks and increment clock by one period. All pending callbacks should be invoked.
Throwable throwable = new Throwable();
rateLimiter.cancelAll(throwable);
clock.addDuration(ONE_MILLISECOND_PERIOD);
AtomicInteger errorInvocations = new AtomicInteger();
IntStream.range(1, 5).forEach(i -> {
try {
callbacks.get(i).get();
} catch (Exception e) {
assertSame(e.getCause(), throwable);
errorInvocations.incrementAndGet();
}
});
assertEquals(errorInvocations.get(), 4);
}
use of com.linkedin.r2.util.Timeout in project rest.li by linkedin.
the class BaseTestSmoothRateLimiter method testConcurrentSubmits.
@Test(timeOut = TEST_TIMEOUT_LONG)
public void testConcurrentSubmits() throws Exception {
Executor executor = Executors.newFixedThreadPool(CONCURRENT_THREADS);
AsyncRateLimiter rateLimiter = getRateLimiter(_scheduledExecutorService, this._executor, _clock);
rateLimiter.setRate(UNLIMITED_PERMITS, ONE_SECOND_PERIOD, UNLIMITED_BURST);
CountDownLatch countDownLatch = new CountDownLatch(CONCURRENT_SUBMITS);
LongAdder successCount = new LongAdder();
LongAdder failureCount = new LongAdder();
for (int i = 0; i < CONCURRENT_SUBMITS; i++) {
executor.execute(() -> rateLimiter.submit(new Callback<None>() {
@Override
public void onError(Throwable e) {
failureCount.increment();
countDownLatch.countDown();
}
@Override
public void onSuccess(None result) {
successCount.increment();
countDownLatch.countDown();
}
}));
}
countDownLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
Assert.assertEquals(successCount.longValue(), CONCURRENT_SUBMITS);
Assert.assertEquals(failureCount.longValue(), 0L);
}
use of com.linkedin.r2.util.Timeout in project rest.li by linkedin.
the class BaseTestSmoothRateLimiter method testMultiSubmitWithinPermits.
@Test(timeOut = TEST_TIMEOUT)
public void testMultiSubmitWithinPermits() throws Exception {
SettableClock clock = new SettableClock();
AsyncRateLimiter rateLimiter = getRateLimiter(_scheduledExecutorService, _executor, clock);
rateLimiter.setRate(128d, ONE_SECOND_PERIOD, UNLIMITED_BURST);
List<FutureCallback<None>> callbacks = new ArrayList<>();
for (int i = 0; i < 128; i++) {
FutureCallback<None> callback = new FutureCallback<>();
callbacks.add(callback);
rateLimiter.submit(callback);
}
for (int i = 0; i < callbacks.size(); i++) {
callbacks.get(i).get();
}
}
use of com.linkedin.r2.util.Timeout 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.util.Timeout in project rest.li by linkedin.
the class HttpNettyClient method sendRequest.
/**
* Sends the request to the {@link ChannelPipeline}.
*/
private void sendRequest(Request request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<StreamResponse> callback) {
final TransportCallback<StreamResponse> decoratedCallback = decorateUserCallback(request, callback);
final NettyClientState state = _state.get();
if (state != NettyClientState.RUNNING) {
decoratedCallback.onResponse(TransportResponseImpl.error(new IllegalStateException("Client is not running")));
return;
}
final long resolvedRequestTimeout = resolveRequestTimeout(requestContext, _requestTimeout);
// Timeout ensures the request callback is always invoked and is cancelled before the
// responsibility of invoking the callback is handed over to the pipeline.
final Timeout<None> timeout = new Timeout<>(_scheduler, resolvedRequestTimeout, TimeUnit.MILLISECONDS, None.none());
timeout.addTimeoutTask(() -> decoratedCallback.onResponse(TransportResponseImpl.error(new TimeoutException("Exceeded request timeout of " + resolvedRequestTimeout + "ms"))));
// resolve address
final SocketAddress address;
try {
TimingContextUtil.markTiming(requestContext, TIMING_KEY);
address = resolveAddress(request, requestContext);
TimingContextUtil.markTiming(requestContext, TIMING_KEY);
} catch (Exception e) {
decoratedCallback.onResponse(TransportResponseImpl.error(e));
return;
}
// Serialize wire attributes
final Request requestWithWireAttrHeaders;
if (request instanceof StreamRequest) {
requestWithWireAttrHeaders = buildRequestWithWireAttributes((StreamRequest) request, wireAttrs);
} else {
MessageType.setMessageType(MessageType.Type.REST, wireAttrs);
requestWithWireAttrHeaders = buildRequestWithWireAttributes((RestRequest) request, wireAttrs);
}
// Gets channel pool
final AsyncPool<Channel> pool;
try {
pool = getChannelPoolManagerPerRequest(requestWithWireAttrHeaders).getPoolForAddress(address);
} catch (IllegalStateException e) {
decoratedCallback.onResponse(TransportResponseImpl.error(e));
return;
}
// Saves protocol version in request context
requestContext.putLocalAttr(R2Constants.HTTP_PROTOCOL_VERSION, _protocolVersion);
final Cancellable pendingGet = pool.get(new ChannelPoolGetCallback(pool, requestWithWireAttrHeaders, requestContext, decoratedCallback, timeout, resolvedRequestTimeout, _streamingTimeout));
if (pendingGet != null) {
timeout.addTimeoutTask(pendingGet::cancel);
}
}
Aggregations