-
-
Notifications
You must be signed in to change notification settings - Fork 16.3k
NioEventLoopGroup deadlocks 1 second on close when using a DnsAddressResolverGroup #5308
Copy link
Copy link
Closed
Description
With Netty 4.1.0.CR7 (probably also with Final)
The NioEventLoop deadlocks 1 second in NioEventLoop#select, at:
int selectedKeys = selector.select(timeoutMillis);
where timeoutMillis is 1000.
The deadlock seem to ahppen when using the DnsAddressResolverGroup opens indirectly an NioDatagramChannel that remains connected since it is closed in a promise of the NioEventLoop.shutdown() - hence the deadlock.
Reproducer:
ServerBootstrap bs = new ServerBootstrap();
bs.channel(NioServerSocketChannel.class);
NioEventLoopGroup group = new NioEventLoopGroup();
bs.group(group);
bs.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new ChannelDuplexHandler(
));
}
});
ChannelFuture server = bs.bind("localhost", 8080);
server.sync();
DnsAddressResolverGroup resolverGroup = new DnsAddressResolverGroup(NioDatagramChannel.class, DnsServerAddresses.defaultAddresses());
Bootstrap bootstrap = new Bootstrap();
bootstrap.resolver(resolverGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.group(group);
bootstrap.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new ChannelDuplexHandler(
));
}
});
ChannelFuture client = bootstrap.connect("localhost", 8080);
client.sync();
client.channel().close().sync();
server.channel().close().sync();
// Try close
resolverGroup.close();
long now = System.currentTimeMillis();
group.shutdownGracefully(0, 10, TimeUnit.SECONDS).addListener(v -> {
long after = System.currentTimeMillis();
System.out.println("stopped " + (after - now));
}).sync();
There is a work around for this:
ServerBootstrap bs = new ServerBootstrap();
bs.channel(NioServerSocketChannel.class);
NioEventLoopGroup group = new NioEventLoopGroup();
bs.group(group);
bs.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new ChannelDuplexHandler(
));
}
});
ChannelFuture server = bs.bind("localhost", 8080);
server.sync();
DnsAddressResolverGroup resolverGroup = new DnsAddressResolverGroup(NioDatagramChannel.class, DnsServerAddresses.defaultAddresses()) {
@Override
protected AddressResolver<InetSocketAddress> newResolver(EventLoop eventLoop, ChannelFactory<? extends DatagramChannel> channelFactory, InetSocketAddress localAddress, DnsServerAddresses nameServerAddresses) throws Exception {
DnsNameResolver resolver = new DnsNameResolverBuilder(eventLoop)
.channelFactory(channelFactory)
.localAddress(localAddress)
.nameServerAddresses(nameServerAddresses)
.build();
return new InetSocketAddressResolver(eventLoop, resolver) {
@Override
public void close() {
resolver.close();
}
};
}
};
Bootstrap bootstrap = new Bootstrap();
bootstrap.resolver(resolverGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.group(group);
bootstrap.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new ChannelDuplexHandler(
));
}
});
ChannelFuture client = bootstrap.connect("localhost", 8080);
client.sync();
client.channel().close().sync();
server.channel().close().sync();
// Try close
resolverGroup.close();
long now = System.currentTimeMillis();
group.shutdownGracefully(0, 10, TimeUnit.SECONDS).addListener(v -> {
long after = System.currentTimeMillis();
System.out.println("stopped " + (after - now));
}).sync();
Reactions are currently unavailable