Closed
Description
Expected Behavior
- When a connection attempt fails, the SocketChannel should be properly closed, and resources should be released.
- Socket management should prevent the number of open sockets from increasing indefinitely during retries.
Current Behavior
- When the target server is down and
TcpNioClientConnectionFactory.buildNewConnection()
attempts to connect,java.net.ConnectException: Connection refused: no further information
is thrown. However, the socket connection is not closed, and the connection retry interval causes the number of sockets to increase indefinitely. - When using
singleUse=false
,clientMode=true
, andretryInterval
, the number of open sockets increases indefinitely until the target server is up.
// TcpNioClientConnectionFactory class
@Override
protected TcpConnectionSupport buildNewConnection() {
try {
SocketChannel socketChannel = SocketChannel.open();
setSocketAttributes(socketChannel.socket());
connect(socketChannel);
TcpNioConnection connection =
this.tcpNioConnectionSupport.createNewConnection(socketChannel, false, isLookupHost(),
getApplicationEventPublisher(), getComponentName());
connection.setUsingDirectBuffers(this.usingDirectBuffers);
connection.setTaskExecutor(getTaskExecutor());
Integer sslHandshakeTimeout = getSslHandshakeTimeout();
if (sslHandshakeTimeout != null && connection instanceof TcpNioSSLConnection) {
((TcpNioSSLConnection) connection).setHandshakeTimeout(sslHandshakeTimeout);
}
TcpConnectionSupport wrappedConnection = wrapConnection(connection);
if (!wrappedConnection.equals(connection)) {
connection.setSenders(getSenders());
}
initializeConnection(wrappedConnection, socketChannel.socket());
if (getSoTimeout() > 0) {
connection.setLastRead(System.currentTimeMillis());
}
this.channelMap.put(socketChannel, connection);
wrappedConnection.publishConnectionOpenEvent();
this.newChannels.add(socketChannel);
this.selector.wakeup();
return wrappedConnection;
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new UncheckedIOException(new IOException(e));
}
}
private void connect(SocketChannel socketChannel) throws IOException, InterruptedException {
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(getHost(), getPort()));
boolean connected = socketChannel.finishConnect();
long timeLeft = getConnectTimeout().toMillis();
while (!connected && timeLeft > 0) {
Thread.sleep(5); // NOSONAR Magic #
connected = socketChannel.finishConnect();
timeLeft -= 5; // NOSONAR Magic #
}
if (!connected) {
throw new IOException("Not connected after connectTimeout");
}
}
Context
- I believe this may cause resource leakage, as each failed connection attempt opens a new socket that is never closed.
- I think that when the server is down and the connection fails, the socket should be properly closed, and resources should be released.
- I'm wondering if adding
socketChannel.close()
in the event of a connection failure would be a good solution, or if I might be misunderstanding the intended behavior ofTcpNioClientConnectionFactory.buildNewConnection()
.