Skip to content

Commit b3668e1

Browse files
committed
Add support for direct DNS lookups behind a feature flag.
1 parent 12a1d4c commit b3668e1

File tree

9 files changed

+142
-6
lines changed

9 files changed

+142
-6
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.eventstore.dbclient;
2+
3+
public final class ClientFeatureFlags {
4+
/**
5+
* Enables direct DNS name resolution, retrieving all IP addresses associated with a given hostname. This
6+
* functionality was initially implemented to support the now-deprecated TCP API. It is particularly useful in
7+
* scenarios involving clusters, where node discovery is enabled.
8+
*/
9+
public static final String DNS_LOOKUP = "dns-lookup";
10+
}

db-client-java/src/main/java/com/eventstore/dbclient/ClusterDiscovery.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package com.eventstore.dbclient;
22

3+
import com.eventstore.dbclient.resolution.DeferredNodeResolution;
4+
import com.eventstore.dbclient.resolution.DeprecatedNodeResolution;
5+
import com.eventstore.dbclient.resolution.FixedSeedsNodeResolution;
6+
import com.eventstore.dbclient.resolution.NodeResolution;
37
import org.slf4j.Logger;
48
import org.slf4j.LoggerFactory;
59

@@ -13,15 +17,18 @@
1317
class ClusterDiscovery implements Discovery {
1418
private static final Logger logger = LoggerFactory.getLogger(ClusterDiscovery.class);
1519
private final NodeSelector nodeSelector;
16-
private final List<InetSocketAddress> seeds;
20+
private final NodeResolution resolution;
1721

1822
ClusterDiscovery(EventStoreDBClientSettings settings) {
1923
this.nodeSelector = new NodeSelector(settings.getNodePreference());
2024

2125
if (settings.isDnsDiscover()) {
22-
this.seeds = Collections.singletonList(settings.getHosts()[0]);
26+
if (settings.getFeatures().contains(ClientFeatureFlags.DNS_LOOKUP))
27+
this.resolution = new DeprecatedNodeResolution(settings.getHosts()[0]);
28+
else
29+
this.resolution = new DeferredNodeResolution(settings.getHosts()[0]);
2330
} else {
24-
this.seeds = Arrays.asList(settings.getHosts());
31+
this.resolution = new FixedSeedsNodeResolution(settings.getHosts());
2532
}
2633
}
2734

@@ -43,7 +50,7 @@ public CompletableFuture<Void> run(ConnectionState state) {
4350
}
4451

4552
void discover(ConnectionState state) {
46-
List<InetSocketAddress> candidates = new ArrayList<>(this.seeds);
53+
List<InetSocketAddress> candidates = resolution.resolve();
4754

4855
if (candidates.size() > 1) {
4956
Collections.shuffle(candidates);

db-client-java/src/main/java/com/eventstore/dbclient/ConnectionSettingsBuilder.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class ConnectionSettingsBuilder {
3131
private Long _defaultDeadline = null;
3232
private List<ClientInterceptor> _interceptors = new ArrayList<>();
3333
private String _tlsCaFile = null;
34+
private Set<String> _features = new HashSet<>();
3435

3536
ConnectionSettingsBuilder() {}
3637

@@ -54,7 +55,8 @@ public EventStoreDBClientSettings buildConnectionSettings() {
5455
_keepAliveInterval,
5556
_defaultDeadline,
5657
_interceptors,
57-
_tlsCaFile);
58+
_tlsCaFile,
59+
_features);
5860
}
5961

6062
/**
@@ -219,6 +221,22 @@ public ConnectionSettingsBuilder tlsCaFile(String filepath) {
219221
return this;
220222
}
221223

224+
/**
225+
* Add feature flags.
226+
*/
227+
public ConnectionSettingsBuilder features(String... features) {
228+
this._features.addAll(Arrays.asList(features));
229+
return this;
230+
}
231+
232+
/**
233+
* Add feature flag.
234+
*/
235+
public ConnectionSettingsBuilder feature(String feature) {
236+
this._features.add(feature);
237+
return this;
238+
}
239+
222240
void parseGossipSeed(String host) {
223241
String[] hostParts = host.split(":");
224242

@@ -436,6 +454,10 @@ static EventStoreDBClientSettings parseFromUrl(ConnectionSettingsBuilder builder
436454
userKeyFile = entry[1];
437455
break;
438456

457+
case "feature":
458+
builder._features.add(value);
459+
break;
460+
439461
default:
440462
logger.warn(String.format("Unknown setting '%s' is ignored", entry[0]));
441463
break;

db-client-java/src/main/java/com/eventstore/dbclient/EventStoreDBClientSettings.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import java.net.InetSocketAddress;
66
import java.util.List;
7+
import java.util.Set;
78

89
/**
910
* Gathers all the settings related to a gRPC client with an EventStoreDB database.
@@ -39,6 +40,7 @@ public class EventStoreDBClientSettings {
3940
private final Long defaultDeadline;
4041
private final List<ClientInterceptor> interceptors;
4142
private final String tlsCaFile;
43+
private final Set<String> features;
4244

4345
/**
4446
* If the dns discovery is enabled.
@@ -160,6 +162,11 @@ public String getTlsCaFile() {
160162
return tlsCaFile;
161163
}
162164

165+
/**
166+
* Feature flags
167+
*/
168+
public Set<String> getFeatures() { return features; }
169+
163170
EventStoreDBClientSettings(
164171
boolean dnsDiscover,
165172
int maxDiscoverAttempts,
@@ -175,7 +182,8 @@ public String getTlsCaFile() {
175182
long keepAliveInterval,
176183
Long defaultDeadline,
177184
List<ClientInterceptor> interceptors,
178-
String tlsCaFile
185+
String tlsCaFile,
186+
Set<String> features
179187
) {
180188
this.dnsDiscover = dnsDiscover;
181189
this.maxDiscoverAttempts = maxDiscoverAttempts;
@@ -192,6 +200,7 @@ public String getTlsCaFile() {
192200
this.defaultDeadline = defaultDeadline;
193201
this.interceptors = interceptors;
194202
this.tlsCaFile = tlsCaFile;
203+
this.features = features;
195204
}
196205

197206
/**
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.eventstore.dbclient.resolution;
2+
3+
import java.net.InetSocketAddress;
4+
import java.util.Collections;
5+
import java.util.List;
6+
7+
public class DeferredNodeResolution implements NodeResolution {
8+
private final InetSocketAddress address;
9+
10+
public DeferredNodeResolution(InetSocketAddress address) {
11+
this.address = address;
12+
}
13+
14+
@Override
15+
public List<InetSocketAddress> resolve() {
16+
return Collections.singletonList(address);
17+
}
18+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.eventstore.dbclient.resolution;
2+
3+
import java.net.InetAddress;
4+
import java.net.InetSocketAddress;
5+
import java.net.UnknownHostException;
6+
import java.util.Arrays;
7+
import java.util.List;
8+
import java.util.stream.Collectors;
9+
10+
public class DeprecatedNodeResolution implements NodeResolution {
11+
private final InetSocketAddress address;
12+
13+
public DeprecatedNodeResolution(InetSocketAddress address) {
14+
this.address = address;
15+
}
16+
17+
@Override
18+
public List<InetSocketAddress> resolve() {
19+
try {
20+
return Arrays.stream(InetAddress.getAllByName(address.getHostName()))
21+
.map(addr -> new InetSocketAddress(addr, address.getPort()))
22+
.collect(Collectors.toList());
23+
} catch (UnknownHostException e) {
24+
throw new RuntimeException(e);
25+
}
26+
}
27+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.eventstore.dbclient.resolution;
2+
3+
import java.net.InetSocketAddress;
4+
import java.util.Arrays;
5+
import java.util.List;
6+
7+
public class FixedSeedsNodeResolution implements NodeResolution {
8+
private final InetSocketAddress[] seeds;
9+
10+
public FixedSeedsNodeResolution(InetSocketAddress[] seeds) {
11+
this.seeds = seeds;
12+
}
13+
14+
@Override
15+
public List<InetSocketAddress> resolve() {
16+
return Arrays.asList(seeds);
17+
}
18+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.eventstore.dbclient.resolution;
2+
3+
import java.net.InetSocketAddress;
4+
import java.util.List;
5+
6+
public interface NodeResolution {
7+
List<InetSocketAddress> resolve();
8+
}

db-client-java/src/test/java/com/eventstore/dbclient/misc/ParseValidConnectionStringTests.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ public static Stream<Arguments> validConnectionStrings() {
110110
Arguments.of(
111111
"esdb://127.0.0.1:21573?userCertFile=/path/to/cert&userKeyFile=/path/to/key",
112112
"{\"dnsDiscover\":false,\"maxDiscoverAttempts\":3,\"discoveryInterval\":500,\"gossipTimeout\":3000,\"nodePreference\":\"leader\",\"tls\":true,\"tlsVerifyCert\":true,\"throwOnAppendFailure\":true,\"hosts\":[{\"address\":\"127.0.0.1\",\"port\":21573}], \"defaultClientCertificate\": {\"clientCertFile\": \"/path/to/cert\", \"clientKeyFile\": \"/path/to/key\"}}"
113+
),
114+
Arguments.of(
115+
"esdb://localhost?feature=foobar",
116+
"{\"dnsDiscover\":false,\"maxDiscoverAttempts\":3,\"discoveryInterval\":500,\"gossipTimeout\":3000,\"nodePreference\":\"leader\",\"tls\":true,\"tlsVerifyCert\":true,\"throwOnAppendFailure\":true,\"hosts\":[{\"address\":\"localhost\",\"port\":2113}], \"features\": \"foobar\"}"
117+
),
118+
Arguments.of(
119+
"esdb://localhost?feature=foobar&feature=baz",
120+
"{\"dnsDiscover\":false,\"maxDiscoverAttempts\":3,\"discoveryInterval\":500,\"gossipTimeout\":3000,\"nodePreference\":\"leader\",\"tls\":true,\"tlsVerifyCert\":true,\"throwOnAppendFailure\":true,\"hosts\":[{\"address\":\"localhost\",\"port\":2113}], \"features\": [\"foobar\", \"baz\"]}"
113121
)
114122
);
115123
}
@@ -215,6 +223,15 @@ private EventStoreDBClientSettings parseJson(String input) throws JsonProcessing
215223
builder.addHost(new InetSocketAddress(host.get("address").asText(), host.get("port").asInt()));
216224
});
217225

226+
if (tree.get("features") != null) {
227+
JsonNode features = tree.get("features");
228+
229+
if (features.isArray())
230+
features.elements().forEachRemaining(feature -> builder.feature(feature.asText()));
231+
else
232+
builder.feature(features.asText());
233+
}
234+
218235
return builder.buildConnectionSettings();
219236
}
220237
}

0 commit comments

Comments
 (0)