Skip to content

Support per-MongoClient DNS lookup configuration #1104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion driver-core/src/main/com/mongodb/ConnectionString.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.mongodb.internal.diagnostics.logging.Loggers;
import com.mongodb.internal.dns.DefaultDnsResolver;
import com.mongodb.lang.Nullable;
import com.mongodb.spi.dns.DnsClient;
import org.bson.UuidRepresentation;

import java.io.UnsupportedEncodingException;
Expand Down Expand Up @@ -296,6 +297,21 @@ public class ConnectionString {
* @since 3.0
*/
public ConnectionString(final String connectionString) {
this(connectionString, null);
}

/**
* Creates a ConnectionString from the given string with the given {@link DnsClient}.
*
* <p>If setting {@link MongoClientSettings#getDnsClient()} explicitly, care should be taken to call this constructor with the same
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unfortunate but I don't see a way around it, as ConnectionString is responsible for TXT record resolution.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[single responsibility] This is where packing configuration together with the logic of processing it together in a public class bit us.

Do we want a ticket about refactoring ConnectionString in 5.0?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just can't think of a concrete plan for it, even if we allow breaking changes. What happens if you call any of the applyConnectioString methods on the setting classes, and then pass a MongoClientSettings in to MongoClient#create. If you then try to apply the TXT record to the MongoClientSettings you have the problem that the settings are supposed to trump the TXT record and so you have to remember in the settings the difference between a value that is the default and the same value that was specified explicitly. Tricky.

Copy link
Member

@stIncMale stIncMale Apr 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On getters

A ConnectionString that does not do what it's not supposed to do should verify the format of the string, may destructure it on components, but should not provide any getters to users (even if currently implementing most of them don't require any IO, who knows what may happen in the future). Therefore, a MongoClientSettings/MongoClientSettings.Builder that was fed a ConnectionString should not provide any getters to users either. I don't think these getters are actually required by users: even if in some bizarre cases a user wants to know what's inside a MongoClientSettings/Builder, he may pack that data in any form needed together with MongoClientSettings/Builder in another structure (a weird requirement needs some additional work on the user side, and is not supported out of the box, that's fine).

If for some reason we end up strongly wanting to provide getters (I hope we don't), we may have two sets of MongoClientSettings/Builder types: as long as a ConnectionString (or any other future mechanism that requires IO or customizable logic similarly to the +srv connection string modifier) is not used, we use the types with getters, otherwise we return a type without getters (see the next section for more details).

On the path forward

[As soon as I posted the first attempt, I realized that the two paths I described are actually different ways of implementing the same approach, so I rewrote this section.]

We may maintain a sequence of updates in MongoClientSettings/Builder:

  • applyConnectionString introduces a new element to the sequence;
  • any other setter is merged together with the immediate previous update as long as that update is not applyConnectionString, otherwise it also introduces a new element to the sequence.
    At the point when we are ready to resolve ConnectionString (and any other settings that require IO or customizable logic), we resolve and merge the updates in the sequence.

The open question here is how to avoid doing multiple rounds of IO due to having multiple applyConnectionString elements (with +srv or something similar) in the sequence. A possible solution (not really):

  • We notice that the "point when we are ready to resolve ConnectionString (and any other settings that require IO or customizable logic)" mentioned previously may even be the MongoClientSettings.build method, as at this point we have all the user customizations available to us. I don't like it, but seems legit. The build method may even have an async version (unlike a constructor of ConnestionString), but our DnsClient and InetAddressResolver a synchronous anyway...
  • We don't allow applying a ConnectionString to a Builder, rather we only allow creating a new Builder from a previously built (and, therefore, fully resolved) MongoClientSettings with a ConnectionString that overrides some of the settings.
  • Now we have at most two elements in the sequence, and we never need to do multiple rounds of IO when resolving settings as there are never multiple applyConnectionString elements.
  • As a side bonus (if one may call it a bonus), MongoClientSettings can now provide getters.

Copy link
Member

@stIncMale stIncMale Apr 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[optional]

Does the above seem like something we could explore further when designing the 5.0 API improvements? If yes, I'll create a ticket. If not, or if we don't really want to have any significant API changes in 5.0, then I won't.

I went to such length in this discussion because the requirement If setting {@link MongoClientSettings#getDnsClient()} explicitly, care should be taken to call this constructor with the same {@link DnsClient} screams at me that we failed at the API design here.

Copy link
Member

@stIncMale stIncMale Apr 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found something related in the SDAM spec https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring-summary.rst:

"
A multi-threaded or asynchronous client's constructor MUST NOT do any I/O. ... The justification is that if clients can be constructed when the deployment is in some states but not in other states, it leads to an unfortunate scenario: When the deployment is passing through a strange state, long-running applications may keep working, but any applications restarted during this period fail.
...
Single-threaded clients also MUST NOT do I/O in the constructor. ...
"

Thile the SDAM spec focuses on specifically client constructor and the state of the MongoDB deployment, the principle of not doing IO in constructors should always be followed for the same reason pointed out in the spec: object creation should not fail because of the temporary unfortunate external state. The constructor of ConnectionString may fail due not network issues, which may result in the whole application failing to start. Our MongoClients.create(String) is a constructor of a client, and it does IO, which violates the SDAM requirement. Even if we had only MongoClients.create(ConnectionString) instead, it would still violate the requirement since creation of a ConnectionString is effectively part of the client's construction.

P.S. This also makes it obvious that the idea of resolving a ConnectionString in MongoClientSettings.build that I expressed above was really bad, and the question on "how to avoid doing multiple rounds of IO due to having multiple applyConnectionString elements (with +srv or something similar) in the sequence" stays very much open. We may talk with other driver teams to see what they do, if we decide to explore this for 5.0.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe what was bad was supporting TXT records. :). I can only say that we knew at the time we were violating the SDAM spec recommendation but didn't see a lot of good options given the API we had to support at the time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* {@link DnsClient}.
*
* @param connectionString the connection string
* @param dnsClient the DNS client with which to resolve TXT record for the mongodb+srv protocol
* @since 4.10
* @see MongoClientSettings#getDnsClient()
*/
public ConnectionString(final String connectionString, @Nullable final DnsClient dnsClient) {
this.connectionString = connectionString;
boolean isMongoDBProtocol = connectionString.startsWith(MONGODB_PREFIX);
isSrvProtocol = connectionString.startsWith(MONGODB_SRV_PREFIX);
Expand Down Expand Up @@ -394,7 +410,7 @@ public ConnectionString(final String connectionString) {
}

String txtRecordsQueryParameters = isSrvProtocol
? new DefaultDnsResolver().resolveAdditionalQueryParametersFromTxtRecords(unresolvedHosts.get(0)) : "";
? new DefaultDnsResolver(dnsClient).resolveAdditionalQueryParametersFromTxtRecords(unresolvedHosts.get(0)) : "";
String connectionStringQueryParameters = unprocessedConnectionString;

Map<String, List<String>> connectionStringOptionsMap = parseOptions(connectionStringQueryParameters);
Expand Down
84 changes: 83 additions & 1 deletion driver-core/src/main/com/mongodb/MongoClientSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import com.mongodb.connection.StreamFactoryFactory;
import com.mongodb.event.CommandListener;
import com.mongodb.lang.Nullable;
import com.mongodb.spi.dns.DnsClient;
import com.mongodb.spi.dns.InetAddressResolver;
import org.bson.UuidRepresentation;
import org.bson.codecs.BsonCodecProvider;
import org.bson.codecs.BsonValueCodecProvider;
Expand Down Expand Up @@ -107,6 +109,8 @@ public final class MongoClientSettings {
private final boolean heartbeatConnectTimeoutSetExplicitly;

private final ContextProvider contextProvider;
private final DnsClient dnsClient;
private final InetAddressResolver inetAddressResolver;

/**
* Gets the default codec registry. It includes the following providers:
Expand Down Expand Up @@ -160,6 +164,39 @@ public static Builder builder(final MongoClientSettings settings) {
return new Builder(settings);
}

/**
* Gets the {@link DnsClient} to use for resolving DNS queries.
*
* <p>If set, it will be used to resolve SRV and TXT records for mongodb+srv connections. Otherwise,
* implementations of {@link com.mongodb.spi.dns.DnsClientProvider} will be discovered via {@link java.util.ServiceLoader}.
* If no implementations are discovered, then {@code com.sun.jndi.dns.DnsContextFactory} will be used to resolve these records.
*
* <p>If applying a connection string to these settings, care must be taken to also pass the same {@link DnsClient} as an argument to
* the {@link ConnectionString} constructor.
*
* @return the DNS client
* @since 4.10
* @see ConnectionString#ConnectionString(String, DnsClient)
*/
@Nullable
public DnsClient getDnsClient() {
return dnsClient;
}

/**
* Gets the {@link InetAddressResolver} to use for looking up the {@link java.net.InetAddress} instances for each host.
*
* <p>If set, it will be used to look up the {@link java.net.InetAddress} for each host, via
* {@link InetAddressResolver#lookupByName(String)}. Otherwise, {@link java.net.InetAddress#getAllByName(String)} will be used.
*
* @return the {@link java.net.InetAddress} resolver
* @since 4.10
*/
@Nullable
public InetAddressResolver getInetAddressResolver() {
return inetAddressResolver;
}

/**
* A builder for {@code MongoClientSettings} so that {@code MongoClientSettings} can be immutable, and to support easier construction
* through chaining.
Expand Down Expand Up @@ -193,6 +230,8 @@ public static final class Builder {
private int heartbeatSocketTimeoutMS;

private ContextProvider contextProvider;
private DnsClient dnsClient;
private InetAddressResolver inetAddressResolver;

private Builder() {
}
Expand All @@ -211,6 +250,7 @@ private Builder(final MongoClientSettings settings) {
credential = settings.getCredential();
uuidRepresentation = settings.getUuidRepresentation();
serverApi = settings.getServerApi();
dnsClient = settings.getDnsClient();
streamFactoryFactory = settings.getStreamFactoryFactory();
autoEncryptionSettings = settings.getAutoEncryptionSettings();
contextProvider = settings.getContextProvider();
Expand All @@ -220,6 +260,7 @@ private Builder(final MongoClientSettings settings) {
socketSettingsBuilder.applySettings(settings.getSocketSettings());
connectionPoolSettingsBuilder.applySettings(settings.getConnectionPoolSettings());
sslSettingsBuilder.applySettings(settings.getSslSettings());

if (settings.heartbeatConnectTimeoutSetExplicitly) {
heartbeatConnectTimeoutMS = settings.heartbeatSocketSettings.getConnectTimeout(MILLISECONDS);
}
Expand Down Expand Up @@ -273,7 +314,7 @@ public Builder applyConnectionString(final ConnectionString connectionString) {
/**
* Applies the {@link LoggerSettings.Builder} block and then sets the loggerSettings.
*
* @param block the block to apply to the LoggerSettins.
* @param block the block to apply to the LoggerSettings.
* @return this
* @see MongoClientSettings#getLoggerSettings()
* @since 4.9
Expand Down Expand Up @@ -580,6 +621,45 @@ public Builder contextProvider(@Nullable final ContextProvider contextProvider)
return this;
}

/**
* Sets the {@link DnsClient} to use for resolving DNS queries.
*
* <p> If set, it will be used to resolve SRV and TXT records for mongodb+srv connections. Otherwise,
* implementation of {@link com.mongodb.spi.dns.DnsClientProvider} will be discovered via {@link java.util.ServiceLoader}
* and used to create an instance of {@link DnsClient}. If no implementation is discovered, then
* {@code com.sun.jndi.dns.DnsContextFactory} will be used to resolve these records.
*
* <p>If applying a connection string to these settings, care must be taken to also pass the same {@link DnsClient} as an
* argument to the {@link ConnectionString} constructor.
*
* @param dnsClient the DNS client
* @return the DNS client
* @since 4.10
* @see ConnectionString#ConnectionString(String, DnsClient)
*/
public Builder dnsClient(@Nullable final DnsClient dnsClient) {
this.dnsClient = dnsClient;
return this;
}

/**
* Sets the {@link InetAddressResolver} to use for looking up the {@link java.net.InetAddress} instances for each host.
*
* <p>If set, it will be used to look up the {@link java.net.InetAddress} for each host, via
* {@link InetAddressResolver#lookupByName(String)}. Otherwise,
* an implementation of {@link com.mongodb.spi.dns.InetAddressResolverProvider} will be discovered via
* {@link java.util.ServiceLoader} and used to create an instance of {@link InetAddressResolver}. If no implementation is
* discovered, {@link java.net.InetAddress#getAllByName(String)} will be used to lookup the {@link java.net.InetAddress}
* instances for a host.
*
* @param inetAddressResolver the InetAddress provider
* @return the {@link java.net.InetAddress} resolver
* @since 4.10
*/
public Builder inetAddressResolver(@Nullable final InetAddressResolver inetAddressResolver) {
this.inetAddressResolver = inetAddressResolver;
return this;
}

// Package-private to provide interop with MongoClientOptions
Builder heartbeatConnectTimeoutMS(final int heartbeatConnectTimeoutMS) {
Expand Down Expand Up @@ -964,6 +1044,8 @@ private MongoClientSettings(final Builder builder) {
compressorList = builder.compressorList;
uuidRepresentation = builder.uuidRepresentation;
serverApi = builder.serverApi;
dnsClient = builder.dnsClient;
inetAddressResolver = builder.inetAddressResolver;
autoEncryptionSettings = builder.autoEncryptionSettings;
heartbeatSocketSettings = SocketSettings.builder()
.readTimeout(builder.heartbeatSocketTimeoutMS == 0
Expand Down
2 changes: 1 addition & 1 deletion driver-core/src/main/com/mongodb/MongoSocketException.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class MongoSocketException extends MongoException {
* @param msg the message
* @param e the cause
*/
MongoSocketException(final String msg, final ServerAddress serverAddress, final Throwable e) {
public MongoSocketException(final String msg, final ServerAddress serverAddress, final Throwable e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looks like we have been throwing this exception to users despite it not being public for a long time. Was it wrong, and MongoSocketException was meant to be public all that time?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class is public, it's just the constructor that was not. Typically the constructors for exceptions are public, if only because they often need to be called from class in the driver that are in a different package.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I was apparently temporarily blinded at the time of writing the first comment. Why do we need to expose constructors of public exceptions in the public API?

There was a situation when I had to make a constructor public (MongoConnectionPoolClearedException), but I explicitly stated that the constructor is not part of the public API.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally need them to be public for the reason mentioned. The VisibleForTesting annotation is not really accurate, but I suppose we could use it for constructors that we don't otherwise want to be public.

Copy link
Member

@stIncMale stIncMale Apr 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[optional]

We generally need them to be public for the reason mentioned.

Being public and being part of the public API is not the same. In this case, the constructor has to be public, but, as far as I can judge from this conversation, does not have to be part of the public API.

The VisibleForTesting annotation is not really accurate

I agree, it should not be used here. But we can document the constructor as not being part of the public API, similarly to how the constructor of MongoConnectionPoolClearedException is documented. By doing so, we reduce the API surface. Do you see reasons why this is a bad idea?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's just a lack of consistency in that the large majority of our exception class constructors are already part of the API and there is not a very clear path to changing that (would we deprecate them all?). So making this one not part of the API doesn't help us all that much. I wouldn't be against a ticket that considers options for shrinking out total constructor API.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super(-2, msg, e);
this.serverAddress = serverAddress;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import com.mongodb.event.ServerListener;
import com.mongodb.event.ServerMonitorListener;
import com.mongodb.lang.Nullable;
import com.mongodb.spi.dns.DnsClient;
import com.mongodb.spi.dns.InetAddressResolver;

import java.util.List;

Expand Down Expand Up @@ -59,7 +61,8 @@ public Cluster createCluster(final ClusterSettings originalClusterSettings, fina
@Nullable final CommandListener commandListener,
@Nullable final String applicationName,
@Nullable final MongoDriverInformation mongoDriverInformation,
final List<MongoCompressor> compressorList, @Nullable final ServerApi serverApi) {
final List<MongoCompressor> compressorList, @Nullable final ServerApi serverApi,
@Nullable final DnsClient dnsClient, @Nullable final InetAddressResolver inetAddressResolver) {

ClusterId clusterId = new ClusterId(applicationName);
ClusterSettings clusterSettings;
Expand Down Expand Up @@ -87,20 +90,20 @@ public Cluster createCluster(final ClusterSettings originalClusterSettings, fina
.build();
}

DnsSrvRecordMonitorFactory dnsSrvRecordMonitorFactory = new DefaultDnsSrvRecordMonitorFactory(clusterId, serverSettings);
DnsSrvRecordMonitorFactory dnsSrvRecordMonitorFactory = new DefaultDnsSrvRecordMonitorFactory(clusterId, serverSettings, dnsClient);

if (clusterSettings.getMode() == ClusterConnectionMode.LOAD_BALANCED) {
ClusterableServerFactory serverFactory = new LoadBalancedClusterableServerFactory(serverSettings,
connectionPoolSettings, internalConnectionPoolSettings, streamFactory, credential, loggerSettings, commandListener,
applicationName, mongoDriverInformation != null ? mongoDriverInformation : MongoDriverInformation.builder().build(),
compressorList, serverApi);
compressorList, serverApi, inetAddressResolver);
return new LoadBalancedCluster(clusterId, clusterSettings, serverFactory, dnsSrvRecordMonitorFactory);
} else {
ClusterableServerFactory serverFactory = new DefaultClusterableServerFactory(serverSettings,
connectionPoolSettings, internalConnectionPoolSettings,
streamFactory, heartbeatStreamFactory, credential, loggerSettings, commandListener, applicationName,
mongoDriverInformation != null ? mongoDriverInformation : MongoDriverInformation.builder().build(), compressorList,
serverApi);
serverApi, inetAddressResolver);

if (clusterSettings.getMode() == ClusterConnectionMode.SINGLE) {
return new SingleServerCluster(clusterId, clusterSettings, serverFactory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.mongodb.event.ServerListener;
import com.mongodb.internal.inject.SameObjectProvider;
import com.mongodb.lang.Nullable;
import com.mongodb.spi.dns.InetAddressResolver;

import java.util.List;

Expand All @@ -54,6 +55,8 @@ public class DefaultClusterableServerFactory implements ClusterableServerFactory
private final List<MongoCompressor> compressorList;
@Nullable
private final ServerApi serverApi;
@Nullable
private final InetAddressResolver inetAddressResolver;

public DefaultClusterableServerFactory(
final ServerSettings serverSettings, final ConnectionPoolSettings connectionPoolSettings,
Expand All @@ -63,7 +66,8 @@ public DefaultClusterableServerFactory(
final LoggerSettings loggerSettings,
@Nullable final CommandListener commandListener,
@Nullable final String applicationName, @Nullable final MongoDriverInformation mongoDriverInformation,
final List<MongoCompressor> compressorList, @Nullable final ServerApi serverApi) {
final List<MongoCompressor> compressorList, @Nullable final ServerApi serverApi,
@Nullable final InetAddressResolver inetAddressResolver) {
this.serverSettings = serverSettings;
this.connectionPoolSettings = connectionPoolSettings;
this.internalConnectionPoolSettings = internalConnectionPoolSettings;
Expand All @@ -76,6 +80,7 @@ public DefaultClusterableServerFactory(
this.mongoDriverInformation = mongoDriverInformation;
this.compressorList = compressorList;
this.serverApi = serverApi;
this.inetAddressResolver = inetAddressResolver;
}

@Override
Expand All @@ -86,11 +91,11 @@ public ClusterableServer create(final Cluster cluster, final ServerAddress serve
ServerMonitor serverMonitor = new DefaultServerMonitor(serverId, serverSettings, cluster.getClock(),
// no credentials, compressor list, or command listener for the server monitor factory
new InternalStreamConnectionFactory(clusterMode, true, heartbeatStreamFactory, null, applicationName,
mongoDriverInformation, emptyList(), loggerSettings, null, serverApi),
mongoDriverInformation, emptyList(), loggerSettings, null, serverApi, inetAddressResolver),
clusterMode, serverApi, sdamProvider);
ConnectionPool connectionPool = new DefaultConnectionPool(serverId,
new InternalStreamConnectionFactory(clusterMode, streamFactory, credential, applicationName,
mongoDriverInformation, compressorList, loggerSettings, commandListener, serverApi),
mongoDriverInformation, compressorList, loggerSettings, commandListener, serverApi, inetAddressResolver),
connectionPoolSettings, internalConnectionPoolSettings, sdamProvider);
ServerListener serverListener = singleServerListener(serverSettings);
SdamServerDescriptionManager sdam = new DefaultSdamServerDescriptionManager(cluster, serverId, serverListener, serverMonitor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import com.mongodb.connection.ClusterId;
import com.mongodb.connection.ServerSettings;
import com.mongodb.internal.dns.DefaultDnsResolver;
import com.mongodb.lang.Nullable;
import com.mongodb.spi.dns.DnsClient;

import static java.util.concurrent.TimeUnit.MILLISECONDS;

Expand All @@ -32,15 +34,17 @@ public class DefaultDnsSrvRecordMonitorFactory implements DnsSrvRecordMonitorFac

private final ClusterId clusterId;
private final long noRecordsRescanFrequency;
private final DnsClient dnsClient;

public DefaultDnsSrvRecordMonitorFactory(final ClusterId clusterId, final ServerSettings serverSettings) {
public DefaultDnsSrvRecordMonitorFactory(final ClusterId clusterId, final ServerSettings serverSettings, @Nullable final DnsClient dnsClient) {
this.clusterId = clusterId;
this.noRecordsRescanFrequency = serverSettings.getHeartbeatFrequency(MILLISECONDS);
this.dnsClient = dnsClient;
}

@Override
public DnsSrvRecordMonitor create(final String hostName, final String srvServiceName, final DnsSrvRecordInitializer dnsSrvRecordInitializer) {
return new DefaultDnsSrvRecordMonitor(hostName, srvServiceName, DEFAULT_RESCAN_FREQUENCY_MILLIS, noRecordsRescanFrequency,
dnsSrvRecordInitializer, clusterId, new DefaultDnsResolver());
dnsSrvRecordInitializer, clusterId, new DefaultDnsResolver(dnsClient));
}
}
Loading