@Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { try { requestHandler.channelInactive(); } catch (RuntimeException e) { logger.error("Exception from request handler while channel is inactive", e); } try { responseHandler.channelInactive(); } catch (RuntimeException e) { logger.error("Exception from response handler while channel is inactive", e); } super.channelInactive(ctx); }
private void deactivateStream() { if (handler instanceof TransportResponseHandler) { // we only have to do this for TransportResponseHandler as it exposes numOutstandingFetches // (there is no extra cleanup that needs to happen) ((TransportResponseHandler) handler).deactivateStream(); } }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { logger.warn("Exception in connection from " + getRemoteAddress(ctx.channel()), cause); requestHandler.exceptionCaught(cause); responseHandler.exceptionCaught(cause); ctx.close(); }
@Override public void exceptionCaught(Throwable cause) { if (numOutstandingRequests() > 0) { String remoteAddress = getRemoteAddress(channel); logger.error("Still have {} requests outstanding when connection from {} is closed", numOutstandingRequests(), remoteAddress); failOutstandingRequests(cause); } }
@Test public void handleFailedFetch() throws Exception { StreamChunkId streamChunkId = new StreamChunkId(1, 0); TransportResponseHandler handler = new TransportResponseHandler(new LocalChannel()); ChunkReceivedCallback callback = mock(ChunkReceivedCallback.class); handler.addFetchRequest(streamChunkId, callback); assertEquals(1, handler.numOutstandingRequests()); handler.handle(new ChunkFetchFailure(streamChunkId, "some error msg")); verify(callback, times(1)).onFailure(eq(0), any()); assertEquals(0, handler.numOutstandingRequests()); }
@Test public void handleFailedRPC() throws Exception { TransportResponseHandler handler = new TransportResponseHandler(new LocalChannel()); RpcResponseCallback callback = mock(RpcResponseCallback.class); handler.addRpcRequest(12345, callback); assertEquals(1, handler.numOutstandingRequests()); handler.handle(new RpcFailure(54321, "uh-oh!")); // should be ignored assertEquals(1, handler.numOutstandingRequests()); handler.handle(new RpcFailure(12345, "oh no")); verify(callback, times(1)).onFailure(any()); assertEquals(0, handler.numOutstandingRequests()); }
@Test public void testActiveStreams() throws Exception { Channel c = new LocalChannel(); c.pipeline().addLast(TransportFrameDecoder.HANDLER_NAME, new TransportFrameDecoder()); TransportResponseHandler handler = new TransportResponseHandler(c); StreamResponse response = new StreamResponse("stream", 1234L, null); StreamCallback cb = mock(StreamCallback.class); handler.addStreamCallback("stream", cb); assertEquals(1, handler.numOutstandingRequests()); handler.handle(response); assertEquals(1, handler.numOutstandingRequests()); handler.deactivateStream(); assertEquals(0, handler.numOutstandingRequests()); StreamFailure failure = new StreamFailure("stream", "uh-oh"); handler.addStreamCallback("stream", cb); assertEquals(1, handler.numOutstandingRequests()); handler.handle(failure); assertEquals(0, handler.numOutstandingRequests()); }
@Test public void failOutstandingStreamCallbackOnClose() throws Exception { Channel c = new LocalChannel(); c.pipeline().addLast(TransportFrameDecoder.HANDLER_NAME, new TransportFrameDecoder()); TransportResponseHandler handler = new TransportResponseHandler(c); StreamCallback cb = mock(StreamCallback.class); handler.addStreamCallback("stream-1", cb); handler.channelInactive(); verify(cb).onFailure(eq("stream-1"), isA(IOException.class)); }
@Test public void failOutstandingStreamCallbackOnException() throws Exception { Channel c = new LocalChannel(); c.pipeline().addLast(TransportFrameDecoder.HANDLER_NAME, new TransportFrameDecoder()); TransportResponseHandler handler = new TransportResponseHandler(c); StreamCallback cb = mock(StreamCallback.class); handler.addStreamCallback("stream-1", cb); handler.exceptionCaught(new IOException("Oops!")); verify(cb).onFailure(eq("stream-1"), isA(IOException.class)); } }
System.nanoTime() - responseHandler.getTimeOfLastRequestNs() > requestTimeoutNs; if (e.state() == IdleState.ALL_IDLE && isActuallyOverdue) { if (responseHandler.numOutstandingRequests() > 0) { String address = getRemoteAddress(ctx.channel()); logger.error("Connection to {} has been quiet for {} ms while there are outstanding " +
handler.addRpcRequest(requestId, callback); getRemoteAddress(channel), future.cause()); logger.error(errorMsg, future.cause()); handler.removeRpcRequest(requestId); channel.close(); try {
handler.addFetchRequest(streamChunkId, callback); getRemoteAddress(channel), future.cause()); logger.error(errorMsg, future.cause()); handler.removeFetchRequest(streamChunkId); channel.close(); try {
/** * Send data to the remote end as a stream. This differs from stream() in that this is a request * to *send* data to the remote end, not to receive it from the remote. * * @param meta meta data associated with the stream, which will be read completely on the * receiving end before the stream itself. * @param data this will be streamed to the remote end to allow for transferring large amounts * of data without reading into memory. * @param callback handles the reply -- onSuccess will only be called when both message and data * are received successfully. */ public long uploadStream( ManagedBuffer meta, ManagedBuffer data, RpcResponseCallback callback) { if (logger.isTraceEnabled()) { logger.trace("Sending RPC to {}", getRemoteAddress(channel)); } long requestId = requestId(); handler.addRpcRequest(requestId, callback); RpcChannelListener listener = new RpcChannelListener(requestId, callback); channel.writeAndFlush(new UploadStream(requestId, meta, data)).addListener(listener); return requestId; }
@Override public void channelRead(ChannelHandlerContext ctx, Object request) throws Exception { if (request instanceof RequestMessage) { requestHandler.handle((RequestMessage) request); } else if (request instanceof ResponseMessage) { responseHandler.handle((ResponseMessage) request); } else { ctx.fireChannelRead(request); } }
/** * Creates the server- and client-side handler which is used to handle both RequestMessages and * ResponseMessages. The channel is expected to have been successfully created, though certain * properties (such as the remoteAddress()) may not be available yet. */ private TransportChannelHandler createChannelHandler(Channel channel, RpcHandler rpcHandler) { TransportResponseHandler responseHandler = new TransportResponseHandler(channel); TransportClient client = new TransportClient(channel, responseHandler); TransportRequestHandler requestHandler = new TransportRequestHandler(channel, client, rpcHandler); return new TransportChannelHandler(client, responseHandler, requestHandler, conf.connectionTimeoutMs(), closeIdleConnections); }
/** * Request to stream the data with the given stream ID from the remote end. * * @param streamId The stream to fetch. * @param callback Object to call with the stream data. */ public void stream(String streamId, StreamCallback callback) { StdChannelListener listener = new StdChannelListener(streamId) { @Override void handleFailure(String errorMsg, Throwable cause) throws Exception { callback.onFailure(streamId, new IOException(errorMsg, cause)); } }; if (logger.isDebugEnabled()) { logger.debug("Sending stream request for {} to {}", streamId, getRemoteAddress(channel)); } // Need to synchronize here so that the callback is added to the queue and the RPC is // written to the socket atomically, so that callbacks are called in the right order // when responses arrive. synchronized (this) { handler.addStreamCallback(streamId, callback); channel.writeAndFlush(new StreamRequest(streamId)).addListener(listener); } }
handler.addFetchRequest(streamChunkId, callback);
@Test public void sendOneWayMessage() throws Exception { final String message = "no reply"; TransportClient client = clientFactory.createClient(TestUtils.getLocalHost(), server.getPort()); try { client.send(JavaUtils.stringToBytes(message)); assertEquals(0, client.getHandler().numOutstandingRequests()); // Make sure the message arrives. long deadline = System.nanoTime() + TimeUnit.NANOSECONDS.convert(10, TimeUnit.SECONDS); while (System.nanoTime() < deadline && oneWayMsgs.size() == 0) { TimeUnit.MILLISECONDS.sleep(10); } assertEquals(1, oneWayMsgs.size()); assertEquals(message, oneWayMsgs.get(0)); } finally { client.close(); } }
@Override public void channelActive(ChannelHandlerContext ctx) throws Exception { try { requestHandler.channelActive(); } catch (RuntimeException e) { logger.error("Exception from request handler while channel is active", e); } try { responseHandler.channelActive(); } catch (RuntimeException e) { logger.error("Exception from response handler while channel is active", e); } super.channelActive(ctx); }
@Test public void handleFailedFetch() throws Exception { StreamChunkId streamChunkId = new StreamChunkId(1, 0); TransportResponseHandler handler = new TransportResponseHandler(new LocalChannel()); ChunkReceivedCallback callback = mock(ChunkReceivedCallback.class); handler.addFetchRequest(streamChunkId, callback); assertEquals(1, handler.numOutstandingRequests()); handler.handle(new ChunkFetchFailure(streamChunkId, "some error msg")); verify(callback, times(1)).onFailure(eq(0), any()); assertEquals(0, handler.numOutstandingRequests()); }