VoidChannelPromise not notified when exception is thrown.
Motivation: When a VoidChannelPromise is used by the user we need to ensure we propergate the exception through the ChannelPipeline otherwise the exception will just be swallowed and so the user has no idea whats going on. Modifications: - Always call tryFailure / trySuccess even when we use the VoidChannelPromise - Add unit test Result: Fixes [#6622].
This commit is contained in:
parent
38b054c65c
commit
119383873d
@ -832,9 +832,9 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap
|
||||
}
|
||||
|
||||
private static void notifyOutboundHandlerException(Throwable cause, ChannelPromise promise) {
|
||||
if (!(promise instanceof VoidChannelPromise)) {
|
||||
PromiseNotificationUtil.tryFailure(promise, cause, logger);
|
||||
}
|
||||
// Only log if the given promise is not of type VoidChannelPromise as tryFailure(...) is expected to return
|
||||
// false.
|
||||
PromiseNotificationUtil.tryFailure(promise, cause, promise instanceof VoidChannelPromise ? null : logger);
|
||||
}
|
||||
|
||||
private void notifyHandlerException(Throwable cause) {
|
||||
|
@ -664,15 +664,15 @@ public final class ChannelOutboundBuffer {
|
||||
}
|
||||
|
||||
private static void safeSuccess(ChannelPromise promise) {
|
||||
if (!(promise instanceof VoidChannelPromise)) {
|
||||
PromiseNotificationUtil.trySuccess(promise, null, logger);
|
||||
}
|
||||
// Only log if the given promise is not of type VoidChannelPromise as trySuccess(...) is expected to return
|
||||
// false.
|
||||
PromiseNotificationUtil.trySuccess(promise, null, promise instanceof VoidChannelPromise ? null : logger);
|
||||
}
|
||||
|
||||
private static void safeFail(ChannelPromise promise, Throwable cause) {
|
||||
if (!(promise instanceof VoidChannelPromise)) {
|
||||
PromiseNotificationUtil.tryFailure(promise, cause, logger);
|
||||
}
|
||||
// Only log if the given promise is not of type VoidChannelPromise as tryFailure(...) is expected to return
|
||||
// false.
|
||||
PromiseNotificationUtil.tryFailure(promise, cause, promise instanceof VoidChannelPromise ? null : logger);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
@ -1073,6 +1073,35 @@ public class DefaultChannelPipelineTest {
|
||||
group.shutdownGracefully(0, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Test(timeout = 3000)
|
||||
public void testVoidPromiseNotify() throws Throwable {
|
||||
ChannelPipeline pipeline1 = new LocalChannel().pipeline();
|
||||
|
||||
EventLoopGroup defaultGroup = new DefaultEventLoopGroup(1);
|
||||
EventLoop eventLoop1 = defaultGroup.next();
|
||||
final Promise<Throwable> promise = eventLoop1.newPromise();
|
||||
final Exception exception = new IllegalArgumentException();
|
||||
try {
|
||||
eventLoop1.register(pipeline1.channel()).syncUninterruptibly();
|
||||
pipeline1.addLast(new ChannelDuplexHandler() {
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
promise.setSuccess(cause);
|
||||
}
|
||||
});
|
||||
pipeline1.write("test", pipeline1.voidPromise());
|
||||
assertSame(exception, promise.syncUninterruptibly().getNow());
|
||||
} finally {
|
||||
pipeline1.channel().close().syncUninterruptibly();
|
||||
defaultGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TestTask implements Runnable {
|
||||
|
||||
private final ChannelPipeline pipeline;
|
||||
|
Loading…
Reference in New Issue
Block a user