Skip to content

Commit e52a276

Browse files
committed
Domain name resolution issues break DefaultConnectionPool when using getAsync
JAVA-3690
1 parent 8802a4b commit e52a276

File tree

4 files changed

+105
-2
lines changed

4 files changed

+105
-2
lines changed

driver-core/src/main/com/mongodb/connection/netty/NettyStream.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,16 @@ public void open() throws IOException {
106106

107107
@Override
108108
public void openAsync(final AsyncCompletionHandler<Void> handler) {
109-
initializeChannel(handler, new LinkedList<SocketAddress>(address.getSocketAddresses()));
109+
Queue<SocketAddress> socketAddressQueue;
110+
111+
try {
112+
socketAddressQueue = new LinkedList<SocketAddress>(address.getSocketAddresses());
113+
} catch (Throwable t) {
114+
handler.failed(t);
115+
return;
116+
}
117+
118+
initializeChannel(handler, socketAddressQueue);
110119
}
111120

112121
private void initializeChannel(final AsyncCompletionHandler<Void> handler, final Queue<SocketAddress> socketAddressQueue) {

driver-core/src/main/com/mongodb/internal/connection/AsynchronousSocketChannelStream.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,16 @@ public AsynchronousSocketChannelStream(final ServerAddress serverAddress, final
5555
@Override
5656
public void openAsync(final AsyncCompletionHandler<Void> handler) {
5757
isTrue("unopened", getChannel() == null);
58-
initializeSocketChannel(handler, new LinkedList<SocketAddress>(serverAddress.getSocketAddresses()));
58+
Queue<SocketAddress> socketAddressQueue;
59+
60+
try {
61+
socketAddressQueue = new LinkedList<SocketAddress>(serverAddress.getSocketAddresses());
62+
} catch (Throwable t) {
63+
handler.failed(t);
64+
return;
65+
}
66+
67+
initializeSocketChannel(handler, socketAddressQueue);
5968
}
6069

6170
private void initializeSocketChannel(final AsyncCompletionHandler<Void> handler, final Queue<SocketAddress> socketAddressQueue) {

driver-core/src/test/functional/com/mongodb/connection/netty/NettyStreamSpecification.groovy

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package com.mongodb.connection.netty
22

33
import category.Slow
4+
import com.mongodb.MongoSocketException
45
import com.mongodb.MongoSocketOpenException
56
import com.mongodb.ServerAddress
7+
import com.mongodb.connection.AsyncCompletionHandler
68
import com.mongodb.connection.SocketSettings
79
import com.mongodb.connection.SslSettings
810
import org.junit.experimental.categories.Category
911
import spock.lang.IgnoreIf
1012
import spock.lang.Specification
1113

14+
import java.util.concurrent.CountDownLatch
1215
import java.util.concurrent.TimeUnit
1316

1417
import static com.mongodb.ClusterFixture.getSslSettings
@@ -64,4 +67,43 @@ class NettyStreamSpecification extends Specification {
6467
then:
6568
thrown(MongoSocketOpenException)
6669
}
70+
71+
@IgnoreIf({ getSslSettings().isEnabled() })
72+
def 'should fail AsyncCompletionHandler if name resolution fails'() {
73+
given:
74+
def serverAddress = Stub(ServerAddress)
75+
def exception = new MongoSocketException('Temporary failure in name resolution', serverAddress)
76+
serverAddress.getSocketAddresses() >> { throw exception }
77+
78+
def stream = new NettyStreamFactory(SocketSettings.builder().connectTimeout(1000, TimeUnit.MILLISECONDS).build(),
79+
SslSettings.builder().build()).create(serverAddress)
80+
def callback = new CallbackErrorHolder()
81+
82+
when:
83+
stream.openAsync(callback)
84+
85+
then:
86+
callback.getError().is(exception)
87+
}
88+
89+
class CallbackErrorHolder implements AsyncCompletionHandler<Void> {
90+
CountDownLatch latch = new CountDownLatch(1)
91+
Throwable throwable = null
92+
93+
Throwable getError() {
94+
latch.countDown()
95+
throwable
96+
}
97+
98+
@Override
99+
void completed(Void r) {
100+
latch.await()
101+
}
102+
103+
@Override
104+
void failed(Throwable t) {
105+
throwable = t
106+
latch.countDown()
107+
}
108+
}
67109
}

driver-core/src/test/functional/com/mongodb/internal/connection/AsyncSocketChannelStreamSpecification.groovy

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.mongodb.internal.connection
22

33
import category.Slow
4+
import com.mongodb.MongoSocketException
45
import com.mongodb.MongoSocketOpenException
56
import com.mongodb.ServerAddress
7+
import com.mongodb.connection.AsyncCompletionHandler
68
import com.mongodb.connection.AsynchronousSocketChannelStreamFactoryFactory
79
import com.mongodb.connection.SocketSettings
810
import com.mongodb.connection.SslSettings
@@ -11,6 +13,7 @@ import spock.lang.IgnoreIf
1113
import spock.lang.Specification
1214

1315
import java.nio.channels.AsynchronousChannelGroup
16+
import java.util.concurrent.CountDownLatch
1417
import java.util.concurrent.Executors
1518

1619
import static com.mongodb.ClusterFixture.getSslSettings
@@ -70,4 +73,44 @@ class AsyncSocketChannelStreamSpecification extends Specification {
7073
then:
7174
thrown(MongoSocketOpenException)
7275
}
76+
77+
@IgnoreIf({ getSslSettings().isEnabled() })
78+
def 'should fail AsyncCompletionHandler if name resolution fails'() {
79+
given:
80+
def serverAddress = Stub(ServerAddress)
81+
def exception = new MongoSocketException('Temporary failure in name resolution', serverAddress)
82+
serverAddress.getSocketAddresses() >> { throw exception }
83+
84+
def stream = new AsynchronousSocketChannelStream(serverAddress,
85+
SocketSettings.builder().connectTimeout(100, MILLISECONDS).build(),
86+
new PowerOfTwoBufferPool(), null)
87+
def callback = new CallbackErrorHolder()
88+
89+
when:
90+
stream.openAsync(callback)
91+
92+
then:
93+
callback.getError().is(exception)
94+
}
95+
96+
class CallbackErrorHolder implements AsyncCompletionHandler<Void> {
97+
CountDownLatch latch = new CountDownLatch(1)
98+
Throwable throwable = null
99+
100+
Throwable getError() {
101+
latch.countDown()
102+
throwable
103+
}
104+
105+
@Override
106+
void completed(Void r) {
107+
latch.await()
108+
}
109+
110+
@Override
111+
void failed(Throwable t) {
112+
throwable = t
113+
latch.countDown()
114+
}
115+
}
73116
}

0 commit comments

Comments
 (0)