Skip to content

Commit e573c1d

Browse files
authored
Fail listener on exception in TcpTransport#openConnection (#101907) (#101955)
Today `TcpTransport#openConnection` may throw exceptions on certain kinds of failure, but other kinds of failure are passed to the listener. This is trappy and not all callers handle it correctly. This commit makes sure that all exceptions are passed to the listener. Closes #100510
1 parent 4d7f289 commit e573c1d

File tree

3 files changed

+50
-15
lines changed

3 files changed

+50
-15
lines changed

docs/changelog/101907.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 101907
2+
summary: Fail listener on exception in `TcpTransport#openConnection`
3+
area: Network
4+
type: bug
5+
issues:
6+
- 100510

server/src/main/java/org/elasticsearch/transport/TcpTransport.java

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -306,22 +306,25 @@ protected ConnectionProfile maybeOverrideConnectionProfile(ConnectionProfile con
306306

307307
@Override
308308
public void openConnection(DiscoveryNode node, ConnectionProfile profile, ActionListener<Transport.Connection> listener) {
309-
310-
Objects.requireNonNull(profile, "connection profile cannot be null");
311-
if (node == null) {
312-
throw new ConnectTransportException(null, "can't open connection to a null node");
313-
}
314-
ConnectionProfile finalProfile = maybeOverrideConnectionProfile(profile);
315-
if (closeLock.readLock().tryLock() == false) {
316-
ensureOpen();
317-
assert false : "should not get here ever because close-write-lock should only be held on shutdown";
318-
throw new ConnectTransportException(node, "failed to acquire close-read-lock");
319-
}
320309
try {
321-
ensureOpen();
322-
initiateConnection(node, finalProfile, listener);
323-
} finally {
324-
closeLock.readLock().unlock();
310+
Objects.requireNonNull(profile, "connection profile cannot be null");
311+
if (node == null) {
312+
throw new ConnectTransportException(null, "can't open connection to a null node");
313+
}
314+
final ConnectionProfile finalProfile = maybeOverrideConnectionProfile(profile);
315+
if (closeLock.readLock().tryLock() == false) {
316+
ensureOpen();
317+
assert false : "should not get here ever because close-write-lock should only be held on shutdown";
318+
throw new ConnectTransportException(node, "failed to acquire close-read-lock");
319+
}
320+
try {
321+
ensureOpen();
322+
initiateConnection(node, finalProfile, listener);
323+
} finally {
324+
closeLock.readLock().unlock();
325+
}
326+
} catch (Exception e) {
327+
listener.onFailure(e);
325328
}
326329
}
327330

test/framework/src/main/java/org/elasticsearch/transport/AbstractSimpleTransportTestCase.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.elasticsearch.action.ActionListenerResponseHandler;
2222
import org.elasticsearch.action.support.PlainActionFuture;
2323
import org.elasticsearch.cluster.node.DiscoveryNode;
24+
import org.elasticsearch.common.component.Lifecycle;
2425
import org.elasticsearch.common.io.stream.BytesStreamOutput;
2526
import org.elasticsearch.common.io.stream.StreamInput;
2627
import org.elasticsearch.common.io.stream.StreamOutput;
@@ -850,6 +851,31 @@ public void handleException(TransportException exp) {
850851
}
851852
}
852853

854+
public void testExceptionOnConnect() {
855+
final Transport transportA = serviceA.getOriginalTransport();
856+
857+
final PlainActionFuture<Transport.Connection> nullProfileFuture = new PlainActionFuture<>();
858+
transportA.openConnection(nodeB, null, nullProfileFuture);
859+
assertTrue(nullProfileFuture.isDone());
860+
expectThrows(ExecutionException.class, NullPointerException.class, nullProfileFuture::get);
861+
862+
final ConnectionProfile profile = ConnectionProfile.buildDefaultConnectionProfile(Settings.EMPTY);
863+
final PlainActionFuture<Transport.Connection> nullNodeFuture = new PlainActionFuture<>();
864+
transportA.openConnection(null, profile, nullNodeFuture);
865+
assertTrue(nullNodeFuture.isDone());
866+
expectThrows(ExecutionException.class, ConnectTransportException.class, nullNodeFuture::get);
867+
868+
serviceA.stop();
869+
assertEquals(Lifecycle.State.STOPPED, transportA.lifecycleState());
870+
serviceA.close();
871+
assertEquals(Lifecycle.State.CLOSED, transportA.lifecycleState());
872+
873+
final PlainActionFuture<Transport.Connection> closedTransportFuture = new PlainActionFuture<>();
874+
transportA.openConnection(nodeB, profile, closedTransportFuture);
875+
assertTrue(closedTransportFuture.isDone());
876+
expectThrows(ExecutionException.class, IllegalStateException.class, closedTransportFuture::get);
877+
}
878+
853879
public void testDisconnectListener() throws Exception {
854880
final CountDownLatch latch = new CountDownLatch(1);
855881
TransportConnectionListener disconnectListener = new TransportConnectionListener() {

0 commit comments

Comments
 (0)