Search in sources :

Example 16 with Timeout

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);
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AsyncRateLimiter(com.linkedin.r2.transport.http.client.AsyncRateLimiter) ArrayList(java.util.ArrayList) SettableClock(com.linkedin.util.clock.SettableClock) None(com.linkedin.common.util.None) FutureCallback(com.linkedin.common.callback.FutureCallback) Test(org.testng.annotations.Test)

Example 17 with Timeout

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);
}
Also used : ClockedExecutor(com.linkedin.test.util.ClockedExecutor) Executor(java.util.concurrent.Executor) FutureCallback(com.linkedin.common.callback.FutureCallback) Callback(com.linkedin.common.callback.Callback) LongAdder(java.util.concurrent.atomic.LongAdder) AsyncRateLimiter(com.linkedin.r2.transport.http.client.AsyncRateLimiter) CountDownLatch(java.util.concurrent.CountDownLatch) None(com.linkedin.common.util.None) Test(org.testng.annotations.Test)

Example 18 with Timeout

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();
    }
}
Also used : AsyncRateLimiter(com.linkedin.r2.transport.http.client.AsyncRateLimiter) ArrayList(java.util.ArrayList) SettableClock(com.linkedin.util.clock.SettableClock) None(com.linkedin.common.util.None) FutureCallback(com.linkedin.common.callback.FutureCallback) Test(org.testng.annotations.Test)

Example 19 with Timeout

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 + ".");
    }
}
Also used : ArrayList(java.util.ArrayList) ClockedExecutor(com.linkedin.test.util.ClockedExecutor) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) SmoothRateLimiter(com.linkedin.r2.transport.http.client.SmoothRateLimiter) None(com.linkedin.common.util.None) Test(org.testng.annotations.Test)

Example 20 with Timeout

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);
    }
}
Also used : Timeout(com.linkedin.r2.util.Timeout) StreamingTimeout(com.linkedin.r2.netty.common.StreamingTimeout) Cancellable(com.linkedin.r2.util.Cancellable) StreamResponse(com.linkedin.r2.message.stream.StreamResponse) Channel(io.netty.channel.Channel) Request(com.linkedin.r2.message.Request) StreamRequest(com.linkedin.r2.message.stream.StreamRequest) RestRequest(com.linkedin.r2.message.rest.RestRequest) TimeoutException(java.util.concurrent.TimeoutException) ShutdownTimeoutException(com.linkedin.r2.netty.common.ShutdownTimeoutException) UnknownHostException(java.net.UnknownHostException) UnknownSchemeException(com.linkedin.r2.netty.common.UnknownSchemeException) StreamRequest(com.linkedin.r2.message.stream.StreamRequest) RestRequest(com.linkedin.r2.message.rest.RestRequest) NettyClientState(com.linkedin.r2.netty.common.NettyClientState) SocketAddress(java.net.SocketAddress) InetSocketAddress(java.net.InetSocketAddress) None(com.linkedin.common.util.None) TimeoutException(java.util.concurrent.TimeoutException) ShutdownTimeoutException(com.linkedin.r2.netty.common.ShutdownTimeoutException)

Aggregations

Test (org.testng.annotations.Test)78 RequestContext (com.linkedin.r2.message.RequestContext)46 CountDownLatch (java.util.concurrent.CountDownLatch)40 TimeoutException (java.util.concurrent.TimeoutException)40 None (com.linkedin.common.util.None)33 FutureCallback (com.linkedin.common.callback.FutureCallback)32 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)26 StreamResponse (com.linkedin.r2.message.stream.StreamResponse)25 URI (java.net.URI)25 RestRequest (com.linkedin.r2.message.rest.RestRequest)21 StreamRequestBuilder (com.linkedin.r2.message.stream.StreamRequestBuilder)21 ByteString (com.linkedin.data.ByteString)19 HashMap (java.util.HashMap)19 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)19 RestResponse (com.linkedin.r2.message.rest.RestResponse)18 StreamRequest (com.linkedin.r2.message.stream.StreamRequest)17 ExecutionException (java.util.concurrent.ExecutionException)17 TransportClient (com.linkedin.r2.transport.common.bridge.client.TransportClient)15 IOException (java.io.IOException)15 TransportCallback (com.linkedin.r2.transport.common.bridge.common.TransportCallback)13