use of com.linkedin.r2.util.Timeout in project rest.li by linkedin.
the class TestDisruptor method testStreamNoDisrupt.
@Test
public void testStreamNoDisrupt() throws Exception {
final RequestContext requestContext = new RequestContext();
final CountDownLatch latch = new CountDownLatch(1);
final AtomicBoolean success = new AtomicBoolean(false);
_client.streamRequest(new StreamRequestBuilder(getHttpURI()).build(EntityStreams.emptyStream()), requestContext, new Callback<StreamResponse>() {
@Override
public void onSuccess(StreamResponse result) {
success.set(true);
latch.countDown();
}
@Override
public void onError(Throwable e) {
success.set(false);
latch.countDown();
}
});
Assert.assertTrue(latch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS), "Test execution timeout");
Assert.assertTrue(success.get(), "Unexpected transport response");
}
use of com.linkedin.r2.util.Timeout 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.util.Timeout in project rest.li by linkedin.
the class Http2StreamCodec method write.
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if (!(msg instanceof RequestWithCallback)) {
ctx.write(msg, promise);
return;
}
Request request = ((RequestWithCallback) msg).request();
Http2ConnectionEncoder encoder = encoder();
int streamId = connection().local().incrementAndGetNextStreamId();
final ChannelFuture headersFuture;
if (request instanceof StreamRequest) {
final StreamRequest streamRequest = (StreamRequest) request;
final Http2Headers http2Headers = NettyRequestAdapter.toHttp2Headers(streamRequest);
final BufferedReader bufferedReader = new BufferedReader(ctx, encoder, streamId, ((RequestWithCallback) msg).handle());
final OrderedEntityStreamReader reader = new OrderedEntityStreamReader(ctx, bufferedReader);
streamRequest.getEntityStream().setReader(reader);
LOG.debug("Sent HTTP/2 HEADERS frame, stream={}, end={}, headers={}, padding={}bytes", new Object[] { streamId, NOT_END_STREAM, http2Headers.size(), NO_PADDING });
headersFuture = encoder.writeHeaders(ctx, streamId, http2Headers, NO_PADDING, NOT_END_STREAM, promise);
headersFuture.addListener(future -> {
if (future.isSuccess()) {
reader.request(BufferedReader.MAX_BUFFERED_CHUNKS);
}
});
} else if (request instanceof RestRequest) {
final RestRequest restRequest = (RestRequest) request;
final Http2Headers headers = NettyRequestAdapter.toHttp2Headers(restRequest);
LOG.debug("Sent HTTP/2 HEADERS frame, stream={}, end={}, headers={}, padding={}bytes", new Object[] { streamId, NOT_END_STREAM, headers.size(), NO_PADDING });
headersFuture = encoder.writeHeaders(ctx, streamId, headers, NO_PADDING, NOT_END_STREAM, promise);
headersFuture.addListener(future -> {
if (future.isSuccess()) {
final ByteBuf data = Unpooled.wrappedBuffer(restRequest.getEntity().asByteBuffer());
LOG.debug("Sent HTTP/2 DATA frame, stream={}, end={}, data={}bytes, padding={}bytes", new Object[] { streamId, END_STREAM, data.readableBytes(), NO_PADDING });
encoder.writeData(ctx, streamId, data, NO_PADDING, END_STREAM, ctx.newPromise());
ctx.channel().flush();
}
});
} else {
// Release the handle to put the channel back to the pool
((RequestWithCallback) msg).handle().release();
throw new IllegalArgumentException("Request is neither StreamRequest or RestRequest");
}
final TransportCallback<?> callback = ((RequestWithCallback) msg).callback();
@SuppressWarnings("unchecked") final TimeoutAsyncPoolHandle<Channel> handle = (TimeoutAsyncPoolHandle<Channel>) ((RequestWithCallback) msg).handle();
headersFuture.addListener(future -> {
if (future.isSuccess()) {
// Sets TransportCallback as a stream property to be retrieved later
Http2PipelinePropertyUtil.set(ctx, connection(), streamId, Http2ClientPipelineInitializer.CALLBACK_ATTR_KEY, callback);
// Sets AsyncPoolHandle as a stream property to be retrieved later
Http2PipelinePropertyUtil.set(ctx, connection(), streamId, Http2ClientPipelineInitializer.CHANNEL_POOL_HANDLE_ATTR_KEY, handle);
// Sets a timeout task to reset stream
// Channel pool handle is also released at timeout
handle.addTimeoutTask(() -> {
LOG.debug("Reset stream upon timeout, stream={}", streamId);
resetStream(ctx, streamId, Http2Error.CANCEL.code(), ctx.newPromise());
ctx.flush();
});
} else {
// Invokes callback onResponse with the error thrown during write header or data
callback.onResponse(TransportResponseImpl.error(future.cause()));
// Releases the handle to put the channel back to the pool
handle.release();
// Resets the stream if a stream is created after we sent header
if (connection().stream(streamId) != null) {
LOG.debug("Reset stream upon timeout, stream={}", streamId);
resetStream(ctx, streamId, Http2Error.CANCEL.code(), ctx.newPromise());
ctx.flush();
}
}
});
}
use of com.linkedin.r2.util.Timeout in project rest.li by linkedin.
the class TestChannelPoolManagerKey method testReturnCorrectIdleTimeout.
/**
* checks if getIdleTimeout() returns SSL timeout in case of SSL client, and normal timeout in case of NON SSL client
*/
@Test
public void testReturnCorrectIdleTimeout() throws NoSuchAlgorithmException {
ChannelPoolManagerKey SSLKey = getKeyBuilder().setSSLContext(SSLContext.getDefault()).setSSLParameters(new SSLParameters()).build();
Assert.assertEquals(SSL_IDLE_TIMEOUT, SSLKey.getIdleTimeout());
ChannelPoolManagerKey plainKey = getKeyBuilder().build();
Assert.assertEquals(IDLE_TIMEOUT, plainKey.getIdleTimeout());
}
use of com.linkedin.r2.util.Timeout in project rest.li by linkedin.
the class TestHttpNettyClient method testNoChannelTimeout.
@Test
public void testNoChannelTimeout() throws InterruptedException {
HttpNettyClient client = new HttpNettyClient(new NoCreations(_scheduler), _scheduler, 500, 500);
RestRequest r = new RestRequestBuilder(URI.create("http://localhost/")).build();
FutureCallback<RestResponse> cb = new FutureCallback<>();
TransportCallback<RestResponse> callback = new TransportCallbackAdapter<>(cb);
client.restRequest(r, new RequestContext(), new HashMap<>(), callback);
try {
// This timeout needs to be significantly larger than the getTimeout of the netty client;
// we're testing that the client will generate its own timeout
cb.get(30, TimeUnit.SECONDS);
Assert.fail("Get was supposed to time out");
} catch (TimeoutException e) {
// TimeoutException means the timeout for Future.get() elapsed and nothing happened.
// Instead, we are expecting our callback to be invoked before the future timeout
// with a timeout generated by the HttpNettyClient.
Assert.fail("Unexpected TimeoutException, should have been ExecutionException", e);
} catch (ExecutionException e) {
verifyCauseChain(e, RemoteInvocationException.class, TimeoutException.class);
}
}
Aggregations