Search in sources :

Example 36 with Callback

use of com.linkedin.common.callback.Callback in project rest.li by linkedin.

the class DegraderLoadBalancerStrategyV3 method checkQuarantineState.

/**
   * checkQuarantineState decides if the D2Quarantine can be enabled or not, by health
   * checking all the trackerClients once. It enables quarantine only if at least one of the
   * clients return success for the checking.
   *
   * The reasons for this checking include:
   *
   * . The default method "OPTIONS" is not always enabled by the service
   * . The user can config any path/method for checking. We do a sanity checking to
   *   make sure the configuration is correct, and service/host responds in time.
   *   Otherwise the host can be kept in quarantine forever if we blindly enable it.
   *
   * This check actually can warm up the R2 connection pool by making a connection to
   * each trackerClient. However since the check happens before any real requests are sent,
   * it generally takes much longer time to get the results, due to different warming up
   * requirements. Therefore the checking will be retried in next update if current check
   * fails.

   *
   * This function is supposed to be protected by the update lock.
   *
   * @param clients
   * @param config
   */
private void checkQuarantineState(List<TrackerClientUpdater> clients, DegraderLoadBalancerStrategyConfig config) {
    Callback<None> healthCheckCallback = new Callback<None>() {

        @Override
        public void onError(Throwable e) {
            // Do nothing as the quarantine is disabled by default
            _rateLimitedLogger.error("Error to enable quarantine. Health checking failed for service {}: ", _state._serviceName, e);
        }

        @Override
        public void onSuccess(None result) {
            if (_state._enableQuarantine.compareAndSet(false, true)) {
                _log.info("Quarantine is enabled for service {}", _state._serviceName);
            }
        }
    };
    // Ideally we would like to healthchecking all the service hosts (ie all TrackerClients) because
    // this can help to warm up the R2 connections to the service hosts, thus speed up the initial access
    // speed when d2client starts to access those hosts. However this can expose/expedite the problem that
    // the d2client host needs too many connections or file handles to all the hosts, when the downstream
    // services have large amount of hosts. Before that problem is addressed, we limit the number of hosts
    // for pre-healthchecking to a small number
    clients.stream().limit(MAX_HOSTS_TO_CHECK_QUARANTINE).forEach(client -> {
        try {
            HealthCheck healthCheckClient = _state.getHealthCheckClient(client);
            if (healthCheckClient == null) {
                healthCheckClient = new HealthCheckClientBuilder().setHealthCheckOperations(config.getHealthCheckOperations()).setHealthCheckPath(config.getHealthCheckPath()).setServicePath(config.getServicePath()).setClock(config.getClock()).setLatency(config.getQuarantineLatency()).setMethod(config.getHealthCheckMethod()).setClient(client.getTrackerClient()).build();
                _state.putHealthCheckClient(client, healthCheckClient);
            }
            healthCheckClient.checkHealth(healthCheckCallback);
        } catch (URISyntaxException e) {
            _log.error("Error to build healthCheckClient ", e);
        }
    });
    // also remove the entries that the corresponding trackerClientUpdaters do not exist anymore
    for (TrackerClientUpdater client : _state._healthCheckMap.keySet()) {
        if (!clients.contains(client)) {
            _state._healthCheckMap.remove(client);
        }
    }
}
Also used : Callback(com.linkedin.common.callback.Callback) HealthCheck(com.linkedin.d2.balancer.util.healthcheck.HealthCheck) HealthCheckClientBuilder(com.linkedin.d2.balancer.util.healthcheck.HealthCheckClientBuilder) URISyntaxException(java.net.URISyntaxException) None(com.linkedin.common.util.None)

Example 37 with Callback

use of com.linkedin.common.callback.Callback in project rest.li by linkedin.

the class TrackerClientTest method testCallTrackingRestRequest.

@Test
public void testCallTrackingRestRequest() throws Exception {
    URI uri = URI.create("http://test.qa.com:1234/foo");
    SettableClock clock = new SettableClock();
    AtomicInteger action = new AtomicInteger(0);
    TransportClient tc = new TransportClient() {

        @Override
        public void restRequest(RestRequest request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<RestResponse> callback) {
            clock.addDuration(5);
            switch(action.get()) {
                // success
                case 0:
                    callback.onResponse(TransportResponseImpl.success(RestResponse.NO_RESPONSE));
                    break;
                // fail with rest exception
                case 1:
                    callback.onResponse(TransportResponseImpl.error(RestException.forError(500, "rest exception")));
                    break;
                // fail with timeout exception
                case 2:
                    callback.onResponse(TransportResponseImpl.error(new RemoteInvocationException(new TimeoutException())));
                    break;
                // fail with other exception
                default:
                    callback.onResponse(TransportResponseImpl.error(new RuntimeException()));
                    break;
            }
        }

        @Override
        public void shutdown(Callback<None> callback) {
        }
    };
    TrackerClient client = createTrackerClient(tc, clock, uri);
    CallTracker callTracker = client.getCallTracker();
    CallTracker.CallStats stats;
    DegraderControl degraderControl = client.getDegraderControl(DefaultPartitionAccessor.DEFAULT_PARTITION_ID);
    client.restRequest(new RestRequestBuilder(uri).build(), new RequestContext(), new HashMap<>(), new TestTransportCallback<>());
    clock.addDuration(5000);
    stats = callTracker.getCallStats();
    Assert.assertEquals(stats.getCallCount(), 1);
    Assert.assertEquals(stats.getErrorCount(), 0);
    Assert.assertEquals(stats.getCallCountTotal(), 1);
    Assert.assertEquals(stats.getErrorCountTotal(), 0);
    Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.0, 0.001);
    action.set(1);
    client.restRequest(new RestRequestBuilder(uri).build(), new RequestContext(), new HashMap<>(), new TestTransportCallback<>());
    clock.addDuration(5000);
    stats = callTracker.getCallStats();
    Assert.assertEquals(stats.getCallCount(), 1);
    Assert.assertEquals(stats.getErrorCount(), 1);
    Assert.assertEquals(stats.getCallCountTotal(), 2);
    Assert.assertEquals(stats.getErrorCountTotal(), 1);
    Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.2, 0.001);
    action.set(2);
    client.restRequest(new RestRequestBuilder(uri).build(), new RequestContext(), new HashMap<>(), new TestTransportCallback<>());
    clock.addDuration(5000);
    stats = callTracker.getCallStats();
    Assert.assertEquals(stats.getCallCount(), 1);
    Assert.assertEquals(stats.getErrorCount(), 1);
    Assert.assertEquals(stats.getCallCountTotal(), 3);
    Assert.assertEquals(stats.getErrorCountTotal(), 2);
    Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.4, 0.001);
    action.set(3);
    client.restRequest(new RestRequestBuilder(uri).build(), new RequestContext(), new HashMap<>(), new TestTransportCallback<>());
    clock.addDuration(5000);
    stats = callTracker.getCallStats();
    Assert.assertEquals(stats.getCallCount(), 1);
    Assert.assertEquals(stats.getErrorCount(), 1);
    Assert.assertEquals(stats.getCallCountTotal(), 4);
    Assert.assertEquals(stats.getErrorCountTotal(), 3);
    Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.2, 0.001);
}
Also used : TransportCallback(com.linkedin.r2.transport.common.bridge.common.TransportCallback) TransportClient(com.linkedin.r2.transport.common.bridge.client.TransportClient) DegraderControl(com.linkedin.util.degrader.DegraderControl) URI(java.net.URI) RestRequest(com.linkedin.r2.message.rest.RestRequest) Callback(com.linkedin.common.callback.Callback) TransportCallback(com.linkedin.r2.transport.common.bridge.common.TransportCallback) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) SettableClock(com.linkedin.util.clock.SettableClock) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) RequestContext(com.linkedin.r2.message.RequestContext) RemoteInvocationException(com.linkedin.r2.RemoteInvocationException) HashMap(java.util.HashMap) Map(java.util.Map) TimeoutException(java.util.concurrent.TimeoutException) CallTracker(com.linkedin.util.degrader.CallTracker) Test(org.testng.annotations.Test)

Example 38 with Callback

use of com.linkedin.common.callback.Callback in project rest.li by linkedin.

the class TrackerClientTest method testCallTrackingStreamRequest.

@Test
public void testCallTrackingStreamRequest() throws Exception {
    URI uri = URI.create("http://test.qa.com:1234/foo");
    SettableClock clock = new SettableClock();
    AtomicInteger action = new AtomicInteger(0);
    TransportClient tc = new TransportClient() {

        @Override
        public void restRequest(RestRequest request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<RestResponse> callback) {
        }

        @Override
        public void streamRequest(StreamRequest request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<StreamResponse> callback) {
            clock.addDuration(5);
            switch(action.get()) {
                // success
                case 0:
                    callback.onResponse(TransportResponseImpl.success(new StreamResponseBuilder().build(EntityStreams.emptyStream())));
                    break;
                // fail with stream exception
                case 1:
                    callback.onResponse(TransportResponseImpl.error(new StreamException(new StreamResponseBuilder().setStatus(500).build(EntityStreams.emptyStream()))));
                    break;
                // fail with timeout exception
                case 2:
                    callback.onResponse(TransportResponseImpl.error(new RemoteInvocationException(new TimeoutException())));
                    break;
                // fail with other exception
                default:
                    callback.onResponse(TransportResponseImpl.error(new RuntimeException()));
                    break;
            }
        }

        @Override
        public void shutdown(Callback<None> callback) {
        }
    };
    TrackerClient client = createTrackerClient(tc, clock, uri);
    CallTracker callTracker = client.getCallTracker();
    CallTracker.CallStats stats;
    DegraderControl degraderControl = client.getDegraderControl(DefaultPartitionAccessor.DEFAULT_PARTITION_ID);
    DelayConsumeCallback delayConsumeCallback = new DelayConsumeCallback();
    client.streamRequest(new StreamRequestBuilder(uri).build(EntityStreams.emptyStream()), new RequestContext(), new HashMap<>(), delayConsumeCallback);
    clock.addDuration(5);
    // we only recorded the time when stream response arrives, but callcompletion.endcall hasn't been called yet.
    Assert.assertEquals(callTracker.getCurrentCallCountTotal(), 0);
    Assert.assertEquals(callTracker.getCurrentErrorCountTotal(), 0);
    // delay
    clock.addDuration(100);
    delayConsumeCallback.consume();
    clock.addDuration(5000);
    // now that we consumed the entity stream, callcompletion.endcall has been called.
    stats = callTracker.getCallStats();
    Assert.assertEquals(stats.getCallCount(), 1);
    Assert.assertEquals(stats.getErrorCount(), 0);
    Assert.assertEquals(stats.getCallCountTotal(), 1);
    Assert.assertEquals(stats.getErrorCountTotal(), 0);
    Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.0, 0.001);
    action.set(1);
    client.streamRequest(new StreamRequestBuilder(uri).build(EntityStreams.emptyStream()), new RequestContext(), new HashMap<>(), delayConsumeCallback);
    clock.addDuration(5);
    // we endcall with error immediately for stream exception, even before the entity is consumed
    Assert.assertEquals(callTracker.getCurrentCallCountTotal(), 2);
    Assert.assertEquals(callTracker.getCurrentErrorCountTotal(), 1);
    delayConsumeCallback.consume();
    clock.addDuration(5000);
    // no change in tracking after entity is consumed
    stats = callTracker.getCallStats();
    Assert.assertEquals(stats.getCallCount(), 1);
    Assert.assertEquals(stats.getErrorCount(), 1);
    Assert.assertEquals(stats.getCallCountTotal(), 2);
    Assert.assertEquals(stats.getErrorCountTotal(), 1);
    Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.2, 0.001);
    action.set(2);
    client.streamRequest(new StreamRequestBuilder(uri).build(EntityStreams.emptyStream()), new RequestContext(), new HashMap<>(), new TestTransportCallback<>());
    clock.addDuration(5);
    Assert.assertEquals(callTracker.getCurrentCallCountTotal(), 3);
    Assert.assertEquals(callTracker.getCurrentErrorCountTotal(), 2);
    clock.addDuration(5000);
    stats = callTracker.getCallStats();
    Assert.assertEquals(stats.getCallCount(), 1);
    Assert.assertEquals(stats.getErrorCount(), 1);
    Assert.assertEquals(stats.getCallCountTotal(), 3);
    Assert.assertEquals(stats.getErrorCountTotal(), 2);
    Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.4, 0.001);
    action.set(3);
    client.streamRequest(new StreamRequestBuilder(uri).build(EntityStreams.emptyStream()), new RequestContext(), new HashMap<>(), new TestTransportCallback<>());
    clock.addDuration(5);
    Assert.assertEquals(callTracker.getCurrentCallCountTotal(), 4);
    Assert.assertEquals(callTracker.getCurrentErrorCountTotal(), 3);
    clock.addDuration(5000);
    stats = callTracker.getCallStats();
    Assert.assertEquals(stats.getCallCount(), 1);
    Assert.assertEquals(stats.getErrorCount(), 1);
    Assert.assertEquals(stats.getCallCountTotal(), 4);
    Assert.assertEquals(stats.getErrorCountTotal(), 3);
    Assert.assertEquals(degraderControl.getCurrentComputedDropRate(), 0.2, 0.001);
}
Also used : TransportCallback(com.linkedin.r2.transport.common.bridge.common.TransportCallback) TransportClient(com.linkedin.r2.transport.common.bridge.client.TransportClient) StreamResponseBuilder(com.linkedin.r2.message.stream.StreamResponseBuilder) DegraderControl(com.linkedin.util.degrader.DegraderControl) URI(java.net.URI) StreamRequestBuilder(com.linkedin.r2.message.stream.StreamRequestBuilder) StreamRequest(com.linkedin.r2.message.stream.StreamRequest) StreamException(com.linkedin.r2.message.stream.StreamException) RestRequest(com.linkedin.r2.message.rest.RestRequest) Callback(com.linkedin.common.callback.Callback) TransportCallback(com.linkedin.r2.transport.common.bridge.common.TransportCallback) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) SettableClock(com.linkedin.util.clock.SettableClock) RequestContext(com.linkedin.r2.message.RequestContext) RemoteInvocationException(com.linkedin.r2.RemoteInvocationException) HashMap(java.util.HashMap) Map(java.util.Map) TimeoutException(java.util.concurrent.TimeoutException) CallTracker(com.linkedin.util.degrader.CallTracker) Test(org.testng.annotations.Test)

Example 39 with Callback

use of com.linkedin.common.callback.Callback in project rest.li by linkedin.

the class ZKFSLoadBalancer method start.

@Override
public void start(final Callback<None> callback) {
    LOG.info("Starting ZKFSLoadBalancer");
    LOG.info("ZK connect string: {}", _connectString);
    LOG.info("ZK session timeout: {}ms", _sessionTimeout);
    LOG.info("ZK initial connect timeout: {}ms", _initialZKTimeout);
    if (_connectString == null || _connectString.isEmpty()) {
        callback.onError(new IllegalArgumentException("ZooKeeper connection string is null or empty"));
        return;
    }
    if (_zkFlagFile == null) {
        LOG.info("ZK flag file not specified");
    } else {
        LOG.info("ZK flag file: {}", _zkFlagFile.getAbsolutePath());
        LOG.info("ZK currently suppressed by flag file: {}", suppressZK());
    }
    _zkConnection = new ZKConnection(_connectString, _sessionTimeout, _shutdownAsynchronously, _isSymlinkAware);
    final TogglingLoadBalancer balancer = _loadBalancerFactory.createLoadBalancer(_zkConnection, _executor);
    // all other cases, we service requests from the old LoadBalancer until the new one is started
    if (_currentLoadBalancer == null) {
        _currentLoadBalancer = balancer;
    }
    Callback<None> wrapped = new Callback<None>() {

        @Override
        public void onSuccess(None none) {
            _currentLoadBalancer = balancer;
            callback.onSuccess(none);
        }

        @Override
        public void onError(Throwable e) {
            callback.onError(e);
        }
    };
    if (!_startupCallback.compareAndSet(null, wrapped)) {
        throw new IllegalStateException("Startup already in progress");
    }
    _executor.execute(new PropertyEventThread.PropertyEvent("startup") {

        @Override
        public void innerRun() {
            _zkConnection.addStateListener(new ZKListener(balancer));
            try {
                _zkConnection.start();
            } catch (Exception e) {
                LOG.error("Failed to start ZooKeeper (bad configuration?), enabling backup stores", e);
                Callback<None> startupCallback = _startupCallback.getAndSet(null);
                // TODO this should never be null
                balancer.enableBackup(startupCallback);
                return;
            }
            LOG.info("Started ZooKeeper");
            _executor.schedule(new Runnable() {

                @Override
                public void run() {
                    Callback<None> startupCallback = _startupCallback.getAndSet(null);
                    if (startupCallback != null) {
                        // Noone has enabled the stores yet either way
                        LOG.error("No response from ZooKeeper within {}ms, enabling backup stores", _initialZKTimeout);
                        balancer.enableBackup(startupCallback);
                    }
                }
            }, _initialZKTimeout, TimeUnit.MILLISECONDS);
        }
    });
}
Also used : ZKConnection(com.linkedin.d2.discovery.stores.zk.ZKConnection) TogglingLoadBalancer(com.linkedin.d2.balancer.util.TogglingLoadBalancer) KeeperException(org.apache.zookeeper.KeeperException) ServiceUnavailableException(com.linkedin.d2.balancer.ServiceUnavailableException) Callback(com.linkedin.common.callback.Callback) None(com.linkedin.common.util.None) PropertyEventThread(com.linkedin.d2.discovery.event.PropertyEventThread)

Example 40 with Callback

use of com.linkedin.common.callback.Callback in project rest.li by linkedin.

the class TestMIMEChainingMultipleSources method generateSuccessChainCallback.

private Callback<StreamResponse> generateSuccessChainCallback(final ClientMultiPartReceiver receiver) {
    return new Callback<StreamResponse>() {

        @Override
        public void onError(Throwable e) {
            Assert.fail();
        }

        @Override
        public void onSuccess(StreamResponse result) {
            final MultiPartMIMEReader reader = MultiPartMIMEReader.createAndAcquireStream(result);
            reader.registerReaderCallback(receiver);
        }
    };
}
Also used : FutureCallback(com.linkedin.common.callback.FutureCallback) Callback(com.linkedin.common.callback.Callback) MultiPartMIMEReaderCallback(com.linkedin.multipart.MultiPartMIMEReaderCallback) StreamResponse(com.linkedin.r2.message.stream.StreamResponse) MultiPartMIMEReader(com.linkedin.multipart.MultiPartMIMEReader)

Aggregations

Callback (com.linkedin.common.callback.Callback)95 Test (org.testng.annotations.Test)64 AfterTest (org.testng.annotations.AfterTest)43 BeforeTest (org.testng.annotations.BeforeTest)43 RequestContext (com.linkedin.r2.message.RequestContext)37 RestResponse (com.linkedin.r2.message.rest.RestResponse)34 ByteString (com.linkedin.data.ByteString)29 RestRequest (com.linkedin.r2.message.rest.RestRequest)28 StreamResponse (com.linkedin.r2.message.stream.StreamResponse)28 AsyncStatusCollectionResource (com.linkedin.restli.server.twitter.AsyncStatusCollectionResource)28 URI (java.net.URI)28 RestLiCallback (com.linkedin.restli.internal.server.RestLiCallback)26 FilterChainCallback (com.linkedin.restli.internal.server.filter.FilterChainCallback)26 ResourceMethodDescriptor (com.linkedin.restli.internal.server.model.ResourceMethodDescriptor)26 ResourceModel (com.linkedin.restli.internal.server.model.ResourceModel)26 RequestExecutionCallback (com.linkedin.restli.server.RequestExecutionCallback)26 RestLiTestHelper.buildResourceModel (com.linkedin.restli.server.test.RestLiTestHelper.buildResourceModel)26 EasyMock.anyObject (org.easymock.EasyMock.anyObject)26 StreamRequest (com.linkedin.r2.message.stream.StreamRequest)25 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)22