Handling Exceptions when Closing
Francis Barber
fedora at barber-family.id.au
Thu Jun 16 09:57:49 EDT 2011
Hello,
I have a question regarding handling exceptions that thrown by a
ChannelHandler when handling a close event. Rather than trying to
explain, I've included a contrived example below to illustrate the point.
The problem is that this code goes off into an infinite loop until
eventually we run out of stack. If an exception is thrown while the
close event is going downstream, an exception event is sent back
upstream. There are two problems here.
(a) The channel actually doesn't get closed because the event doesn't
reach the sink. While this isn't necessarily wrong, the ChannelFuture
doesn't get told about the exception so it is never "done".
(b) I would be able to set failure on the ChannelFuture myself in my
upstream exception handler, but the original event (the close event) is
lost in AbstractChannelSink.exceptionCaught(). This makes it impossible
for my exception handler to tell that the channel was in the process of
being closed, so naturally it decides to close the channel again, and
around we go.
Is this a bug, or is there a different way I'm meant to handle exceptions?
Many thanks,
Frank.
import org.jboss.netty.bootstrap.*;
import org.jboss.netty.channel.*;
import org.junit.Test;
public class Experiment {
@Test
public void test() {
ServerBootstrap serverBootstrap = new ServerBootstrap(new
DefaultLocalServerChannelFactory());
serverBootstrap.setPipelineFactory(Channels.pipelineFactory(Channels.pipeline()));
serverBootstrap.bind(new LocalAddress("server"));
ClientBootstrap clientBootstrap = new ClientBootstrap(new
DefaultLocalClientChannelFactory());
clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("close-handler", new
SimpleChannelDownstreamHandler() {
@Override
public void closeRequested(ChannelHandlerContext ctx,
ChannelStateEvent e)
throws Exception {
throw new RuntimeException("test");
}
});
pipeline.addLast("interceptor-up", new
SimpleChannelUpstreamHandler() {
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
ExceptionEvent e) throws Exception {
// Can't tell that the exception was thrown during close
e.getCause().printStackTrace();
ctx.getChannel().close();
}
});
return pipeline;
}
});
ChannelFuture f = clientBootstrap.connect(new LocalAddress("server"));
f.awaitUninterruptibly();
// The channel is not closed and this will wait forever
f.getChannel().close().awaitUninterruptibly();
}
}
More information about the netty-users
mailing list