use of com.linkedin.r2.netty.common.NettyClientState 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);
}
}
use of com.linkedin.r2.netty.common.NettyClientState in project rest.li by linkedin.
the class HttpNettyClient method doWriteRequest.
@Override
protected void doWriteRequest(RestRequest request, RequestContext requestContext, SocketAddress address, Map<String, String> wireAttrs, final TimeoutTransportCallback<RestResponse> callback, long requestTimeout) {
final RestRequest newRequest = new RestRequestBuilder(request).overwriteHeaders(WireAttributeHelper.toWireAttributes(wireAttrs)).build();
requestContext.putLocalAttr(R2Constants.HTTP_PROTOCOL_VERSION, HttpProtocolVersion.HTTP_1_1);
final AsyncPool<Channel> pool;
try {
pool = getChannelPoolManagerPerRequest(request).getPoolForAddress(address);
} catch (IllegalStateException e) {
errorResponse(callback, e);
return;
}
final Cancellable pendingGet = pool.get(new Callback<Channel>() {
@Override
public void onSuccess(final Channel channel) {
// This handler ensures the channel is returned to the pool at the end of the
// Netty pipeline.
channel.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).set(pool);
callback.addTimeoutTask(() -> {
AsyncPool<Channel> pool1 = channel.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).getAndSet(null);
if (pool1 != null) {
pool1.dispose(channel);
}
});
TransportCallback<RestResponse> sslTimingCallback = SslHandshakeTimingHandler.getSslTimingCallback(channel, requestContext, callback);
// This handler invokes the callback with the response once it arrives.
channel.attr(RAPResponseHandler.CALLBACK_ATTR_KEY).set(sslTimingCallback);
// Set the session validator requested by the user
SslSessionValidator sslSessionValidator = (SslSessionValidator) requestContext.getLocalAttr(R2Constants.REQUESTED_SSL_SESSION_VALIDATOR);
channel.attr(NettyChannelAttributes.SSL_SESSION_VALIDATOR).set(sslSessionValidator);
final NettyClientState state = _state.get();
if (state == NettyClientState.REQUESTS_STOPPING || state == NettyClientState.SHUTDOWN) {
// In this case, we acquired a channel from the pool as request processing is halting.
// The shutdown task might not timeout this callback, since it may already have scanned
// all the channels for pending requests before we set the callback as the channel
// attachment. The TimeoutTransportCallback ensures the user callback in never
// invoked more than once, so it is safe to invoke it unconditionally.
errorResponse(sslTimingCallback, new TimeoutException("Operation did not complete before shutdown"));
// The channel is usually release in two places: timeout or in the netty pipeline.
// Since we call the callback above, the timeout associated will be never invoked. On top of that
// we never send the request to the pipeline (due to the return statement), and nobody is releasing the channel
// until the channel is forcefully closed by the shutdownTimeout. Therefore we have to release it here
AsyncPool<Channel> pool = channel.attr(ChannelPoolHandler.CHANNEL_POOL_ATTR_KEY).getAndSet(null);
if (pool != null) {
pool.put(channel);
}
return;
}
// here we want the exception in outbound operations to be passed back through pipeline so that
// the user callback would be invoked with the exception and the channel can be put back into the pool
channel.writeAndFlush(newRequest).addListener(new ErrorChannelFutureListener());
}
@Override
public void onError(Throwable e) {
errorResponse(callback, e);
}
});
if (pendingGet != null) {
callback.addTimeoutTask(pendingGet::cancel);
}
}
use of com.linkedin.r2.netty.common.NettyClientState in project rest.li by linkedin.
the class AbstractNettyClient method writeRequest.
/**
* This method calls the user defined method {@link AbstractNettyClient#doWriteRequest(Request, RequestContext, SocketAddress, Map, TimeoutTransportCallback, long)}
* after having checked that the client is still running and resolved the DNS
*/
private void writeRequest(Req request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<Res> callback) {
// Decorates callback
TransportCallback<Res> executionCallback = getExecutionCallback(callback);
TransportCallback<Res> shutdownAwareCallback = getShutdownAwareCallback(executionCallback);
// Resolves request timeout
long requestTimeout = HttpNettyClient.resolveRequestTimeout(requestContext, _requestTimeout);
// 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
TimeoutTransportCallback<Res> timeoutCallback = new TimeoutTransportCallback<>(_scheduler, requestTimeout, TimeUnit.MILLISECONDS, shutdownAwareCallback, "Exceeded request timeout of " + requestTimeout + "ms");
// check lifecycle
NettyClientState state = _state.get();
if (state != NettyClientState.RUNNING) {
errorResponse(callback, new IllegalStateException("Client is " + state));
return;
}
// resolve address
final SocketAddress address;
try {
TimingContextUtil.markTiming(requestContext, TIMING_KEY);
address = HttpNettyClient.resolveAddress(request, requestContext);
TimingContextUtil.markTiming(requestContext, TIMING_KEY);
} catch (UnknownHostException | UnknownSchemeException e) {
errorResponse(callback, e);
return;
}
doWriteRequest(request, requestContext, address, wireAttrs, timeoutCallback, requestTimeout);
}
Aggregations