Search in sources :

Example 1 with TimeoutCallback

use of com.linkedin.r2.transport.http.client.TimeoutCallback in project rest.li by linkedin.

the class HttpNettyClient method shutdown.

@Override
public void shutdown(final Callback<None> callback) {
    LOG.info("Shutdown requested");
    if (_state.compareAndSet(State.RUNNING, State.SHUTTING_DOWN)) {
        LOG.info("Shutting down");
        final long deadline = System.currentTimeMillis() + _shutdownTimeout;
        TimeoutCallback<None> closeChannels = new TimeoutCallback<None>(_scheduler, _shutdownTimeout, TimeUnit.MILLISECONDS, new Callback<None>() {

            private void finishShutdown() {
                _state.set(State.REQUESTS_STOPPING);
                // Timeout any waiters which haven't received a Channel yet
                for (Callback<Channel> callback : _channelPoolManager.cancelWaiters()) {
                    callback.onError(new TimeoutException("Operation did not complete before shutdown"));
                }
                // Timeout any requests still pending response
                for (Channel c : _allChannels) {
                    TransportCallback<RestResponse> callback = c.attr(RAPResponseHandler.CALLBACK_ATTR_KEY).getAndRemove();
                    if (callback != null) {
                        errorResponse(callback, new TimeoutException("Operation did not complete before shutdown"));
                    }
                }
                // Close all active and idle Channels
                final TimeoutRunnable afterClose = new TimeoutRunnable(_scheduler, deadline - System.currentTimeMillis(), TimeUnit.MILLISECONDS, new Runnable() {

                    @Override
                    public void run() {
                        _state.set(State.SHUTDOWN);
                        LOG.info("Shutdown complete");
                        callback.onSuccess(None.none());
                    }
                }, "Timed out waiting for channels to close, continuing shutdown");
                _allChannels.close().addListener(new ChannelGroupFutureListener() {

                    @Override
                    public void operationComplete(ChannelGroupFuture channelGroupFuture) throws Exception {
                        if (!channelGroupFuture.isSuccess()) {
                            LOG.warn("Failed to close some connections, ignoring");
                        }
                        afterClose.run();
                    }
                });
            }

            @Override
            public void onSuccess(None none) {
                LOG.info("All connection pools shut down, closing all channels");
                finishShutdown();
            }

            @Override
            public void onError(Throwable e) {
                LOG.warn("Error shutting down HTTP connection pools, ignoring and continuing shutdown", e);
                finishShutdown();
            }
        }, "Connection pool shutdown timeout exceeded (" + _shutdownTimeout + "ms)");
        _channelPoolManager.shutdown(closeChannels);
        _jmxManager.onProviderShutdown(_channelPoolManager);
    } else {
        callback.onError(new IllegalStateException("Shutdown has already been requested."));
    }
}
Also used : TransportCallback(com.linkedin.r2.transport.common.bridge.common.TransportCallback) TimeoutRunnable(com.linkedin.r2.util.TimeoutRunnable) ChannelGroupFuture(io.netty.channel.group.ChannelGroupFuture) NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) Channel(io.netty.channel.Channel) ChannelGroupFutureListener(io.netty.channel.group.ChannelGroupFutureListener) TransportCallback(com.linkedin.r2.transport.common.bridge.common.TransportCallback) Callback(com.linkedin.common.callback.Callback) TimeoutRunnable(com.linkedin.r2.util.TimeoutRunnable) None(com.linkedin.common.util.None) TimeoutException(java.util.concurrent.TimeoutException)

Example 2 with TimeoutCallback

use of com.linkedin.r2.transport.http.client.TimeoutCallback in project rest.li by linkedin.

the class AsyncPoolImpl method create.

/**
 * DO NOT call this method while holding the lock!  It invokes user code.
 */
private void create() {
    trc("initiating object creation");
    _rateLimiter.submit(new Task() {

        @Override
        public void run(final SimpleCallback callback) {
            boolean shouldIgnore;
            synchronized (_lock) {
                // Ignore the object creation if no one is waiting for the object and the pool already has _minSize objects
                int totalObjects = _checkedOut + _idle.size();
                shouldIgnore = _waiters.size() == 0 && totalObjects >= _minSize;
                if (shouldIgnore) {
                    _statsTracker.incrementIgnoredCreation();
                    if (_poolSize >= 1) {
                        // _poolSize also include the count of creation requests pending. So we have to make sure the pool size
                        // count is updated when we ignore the creation request.
                        _poolSize--;
                    }
                }
            }
            if (shouldIgnore) {
                callback.onDone();
                return;
            }
            // Lets not trust the _lifecycle to timely return a response here.
            // Embedding the callback inside a timeout callback (ObjectCreationTimeoutCallback)
            // to force a response within creationTimeout deadline to reclaim the object slot in the pool
            _lifecycle.create(new TimeoutCallback<>(_timeoutExecutor, _creationTimeout, TimeUnit.MILLISECONDS, new Callback<T>() {

                @Override
                public void onSuccess(T t) {
                    synchronized (_lock) {
                        _statsTracker.incrementCreated();
                        _lastCreateError = null;
                    }
                    add(t);
                    callback.onDone();
                }

                @Override
                public void onError(final Throwable e) {
                    // Note we drain all waiters and cancel all pending creates if a create fails.
                    // When a create fails, rate-limiting logic will be applied.  In this case,
                    // we may be initiating creations at a lower rate than incoming requests.  While
                    // creations are suppressed, it is better to deny all waiters and let them see
                    // the real reason (this exception) rather than keep them around to eventually
                    // get an unhelpful timeout error
                    final Collection<Callback<T>> waitersDenied;
                    final Collection<Task> cancelledCreate = _rateLimiter.cancelPendingTasks();
                    boolean create;
                    synchronized (_lock) {
                        _statsTracker.incrementCreateErrors();
                        _lastCreateError = e;
                        // Cancel all waiters in the rate limiter
                        if (!_waiters.isEmpty()) {
                            waitersDenied = cancelWaiters();
                        } else {
                            waitersDenied = Collections.<Callback<T>>emptyList();
                        }
                        // reclaim the slot in the pool
                        create = objectDestroyed(1 + cancelledCreate.size());
                    }
                    // lets fail all the waiters with the object creation error
                    for (Callback<T> denied : waitersDenied) {
                        try {
                            denied.onError(e);
                        } catch (Exception ex) {
                            LOG.error("Encountered error while invoking error waiter callback", ex);
                        }
                    }
                    // Now after cancelling all the pending tasks, lets make sure to back off on the creation
                    _rateLimiter.incrementPeriod();
                    // the min poolSize
                    if (create) {
                        create();
                    }
                    LOG.debug(_poolName + ": object creation failed", e);
                    callback.onDone();
                }
            }, () -> new ObjectCreationTimeoutException("Exceeded creation timeout of " + _creationTimeout + "ms: in Pool: " + _poolName)));
        }
    });
}
Also used : Task(com.linkedin.r2.transport.http.client.RateLimiter.Task) Callback(com.linkedin.common.callback.Callback) SimpleCallback(com.linkedin.common.callback.SimpleCallback) Collection(java.util.Collection) SimpleCallback(com.linkedin.common.callback.SimpleCallback) SizeLimitExceededException(com.linkedin.r2.SizeLimitExceededException)

Example 3 with TimeoutCallback

use of com.linkedin.r2.transport.http.client.TimeoutCallback in project rest.li by linkedin.

the class ChannelPoolManagerImpl method shutdown.

public void shutdown(final Callback<None> callback, final Runnable callbackStopRequest, final Runnable callbackShutdown, long shutdownTimeout) {
    final long deadline = System.currentTimeMillis() + shutdownTimeout;
    Callback<None> closeChannels = new TimeoutCallback<>(_scheduler, shutdownTimeout, TimeUnit.MILLISECONDS, new Callback<None>() {

        private void finishShutdown() {
            callbackStopRequest.run();
            // Timeout any waiters which haven't received a Channel yet
            cancelWaiters();
            // Close all active and idle Channels
            final TimeoutRunnable afterClose = new TimeoutRunnable(_scheduler, deadline - System.currentTimeMillis(), TimeUnit.MILLISECONDS, () -> {
                callbackShutdown.run();
                LOG.info("Shutdown complete");
                callback.onSuccess(None.none());
            }, "Timed out waiting for channels to close, continuing shutdown");
            _allChannels.close().addListener((ChannelGroupFutureListener) channelGroupFuture -> {
                if (!channelGroupFuture.isSuccess()) {
                    LOG.warn("Failed to close some connections, ignoring");
                }
                afterClose.run();
            });
        }

        @Override
        public void onSuccess(None none) {
            LOG.info("All connection pools shut down, closing all channels");
            finishShutdown();
        }

        @Override
        public void onError(Throwable e) {
            LOG.warn("Error shutting down HTTP connection pools, ignoring and continuing shutdown", e);
            finishShutdown();
        }
    }, "Connection pool shutdown timeout exceeded");
    shutdownPool(closeChannels);
}
Also used : TimeoutRunnable(com.linkedin.r2.util.TimeoutRunnable) ChannelGroupFutureListener(io.netty.channel.group.ChannelGroupFutureListener) None(com.linkedin.common.util.None) TimeoutCallback(com.linkedin.r2.transport.http.client.TimeoutCallback)

Example 4 with TimeoutCallback

use of com.linkedin.r2.transport.http.client.TimeoutCallback in project rest.li by linkedin.

the class AbstractNettyStreamClient method writeRequestWithTimeout.

private void writeRequestWithTimeout(final StreamRequest request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<StreamResponse> callback) {
    StreamExecutionCallback executionCallback = new StreamExecutionCallback(_callbackExecutors, callback);
    // By wrapping the callback in a Timeout callback before passing it along, we deny the rest
    // of the code access to the unwrapped callback.  This ensures two things:
    // 1. The user callback will always be invoked, since the Timeout will eventually expire
    // 2. The user callback is never invoked more than once
    final TimeoutTransportCallback<StreamResponse> timeoutCallback = new TimeoutTransportCallback<StreamResponse>(_scheduler, _requestTimeout, TimeUnit.MILLISECONDS, executionCallback, _requestTimeoutMessage);
    final StreamRequest requestWithWireAttrHeaders = request.builder().overwriteHeaders(WireAttributeHelper.toWireAttributes(wireAttrs)).build(request.getEntityStream());
    // talk to legacy R2 servers without problem if they're just using restRequest (full request).
    if (isFullRequest(requestContext)) {
        Messages.toRestRequest(requestWithWireAttrHeaders, new Callback<RestRequest>() {

            @Override
            public void onError(Throwable e) {
                errorResponse(timeoutCallback, e);
            }

            @Override
            public void onSuccess(RestRequest restRequest) {
                writeRequest(restRequest, requestContext, timeoutCallback);
            }
        });
    } else {
        writeRequest(requestWithWireAttrHeaders, requestContext, timeoutCallback);
    }
}
Also used : RestRequest(com.linkedin.r2.message.rest.RestRequest) StreamResponse(com.linkedin.r2.message.stream.StreamResponse) StreamRequest(com.linkedin.r2.message.stream.StreamRequest)

Example 5 with TimeoutCallback

use of com.linkedin.r2.transport.http.client.TimeoutCallback in project rest.li by linkedin.

the class SimpleLoadBalancer method getDarkClusterConfigMap.

@Override
public void getDarkClusterConfigMap(String clusterName, Callback<DarkClusterConfigMap> callback) {
    Callback<DarkClusterConfigMap> wrappedCallback = new TimeoutCallback<>(_executor, _timeout, _unit, callback);
    _state.listenToCluster(clusterName, (type, name) -> {
        ClusterProperties clusterProperties = _state.getClusterProperties(clusterName).getProperty();
        DarkClusterConfigMap darkClusterConfigMap = clusterProperties != null ? clusterProperties.accessDarkClusters() : new DarkClusterConfigMap();
        wrappedCallback.onSuccess(darkClusterConfigMap);
    });
}
Also used : DarkClusterConfigMap(com.linkedin.d2.DarkClusterConfigMap) ClusterProperties(com.linkedin.d2.balancer.properties.ClusterProperties) TimeoutCallback(com.linkedin.r2.transport.http.client.TimeoutCallback)

Aggregations

Callback (com.linkedin.common.callback.Callback)4 TimeoutCallback (com.linkedin.r2.transport.http.client.TimeoutCallback)4 FutureCallback (com.linkedin.common.callback.FutureCallback)2 None (com.linkedin.common.util.None)2 LoadBalancerStateListenerCallback (com.linkedin.d2.balancer.LoadBalancerState.LoadBalancerStateListenerCallback)2 NullStateListenerCallback (com.linkedin.d2.balancer.LoadBalancerState.NullStateListenerCallback)2 ServiceUnavailableException (com.linkedin.d2.balancer.ServiceUnavailableException)2 ServiceProperties (com.linkedin.d2.balancer.properties.ServiceProperties)2 PropertyEventShutdownCallback (com.linkedin.d2.discovery.event.PropertyEventThread.PropertyEventShutdownCallback)2 TimeoutRunnable (com.linkedin.r2.util.TimeoutRunnable)2 ChannelGroupFutureListener (io.netty.channel.group.ChannelGroupFutureListener)2 SimpleCallback (com.linkedin.common.callback.SimpleCallback)1 DarkClusterConfigMap (com.linkedin.d2.DarkClusterConfigMap)1 ClusterProperties (com.linkedin.d2.balancer.properties.ClusterProperties)1 SizeLimitExceededException (com.linkedin.r2.SizeLimitExceededException)1 RestRequest (com.linkedin.r2.message.rest.RestRequest)1 StreamRequest (com.linkedin.r2.message.stream.StreamRequest)1 StreamResponse (com.linkedin.r2.message.stream.StreamResponse)1 NettyClientState (com.linkedin.r2.netty.common.NettyClientState)1 UnknownSchemeException (com.linkedin.r2.netty.common.UnknownSchemeException)1