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."));
}
}
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)));
}
});
}
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);
}
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);
}
}
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);
});
}
Aggregations