-
Notifications
You must be signed in to change notification settings - Fork 180
/
DefaultDnsServiceDiscovererBuilder.java
245 lines (226 loc) · 9.92 KB
/
DefaultDnsServiceDiscovererBuilder.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
/*
* Copyright © 2018 Apple Inc. and the ServiceTalk project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.servicetalk.dns.discovery.netty;
import io.servicetalk.client.api.ServiceDiscoverer;
import io.servicetalk.client.api.ServiceDiscovererEvent;
import io.servicetalk.transport.api.HostAndPort;
import io.servicetalk.transport.api.IoExecutor;
import io.netty.resolver.dns.DnsNameResolverTimeoutException;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.time.Duration;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import static io.servicetalk.dns.discovery.netty.DnsClients.asHostAndPortDiscoverer;
import static io.servicetalk.dns.discovery.netty.DnsClients.asSrvDiscoverer;
import static io.servicetalk.transport.netty.internal.GlobalExecutionContext.globalExecutionContext;
import static java.util.Objects.requireNonNull;
/**
* Builder for <a href="https://tools.ietf.org/html/rfc1035">DNS</a> {@link ServiceDiscoverer} which will attempt to
* resolve {@code A}, {@code AAAA}, {@code CNAME}, and {@code SRV} type queries.
*/
public final class DefaultDnsServiceDiscovererBuilder {
@Nullable
private DnsServerAddressStreamProvider dnsServerAddressStreamProvider;
@Nullable
private DnsResolverAddressTypes dnsResolverAddressTypes;
@Nullable
private Integer ndots;
private Predicate<Throwable> invalidateHostsOnDnsFailure = defaultInvalidateHostsOnDnsFailurePredicate();
@Nullable
private Boolean optResourceEnabled;
@Nullable
private IoExecutor ioExecutor;
@Nullable
private Duration queryTimeout;
private int minTTLSeconds = 10;
@Nullable
private DnsClientFilterFactory filterFactory;
@Nullable
private DnsServiceDiscovererObserver observer;
/**
* The minimum allowed TTL. This will be the minimum poll interval.
*
* @param minTTLSeconds The minimum amount of time a cache entry will be considered valid (in seconds).
* @return {@code this}.
*/
public DefaultDnsServiceDiscovererBuilder minTTL(final int minTTLSeconds) {
if (minTTLSeconds < 1) {
throw new IllegalArgumentException("minTTLSeconds: " + minTTLSeconds + " (expected > 1)");
}
this.minTTLSeconds = minTTLSeconds;
return this;
}
/**
* Set the {@link DnsServerAddressStreamProvider} which determines which DNS server should be used per query.
*
* @param dnsServerAddressStreamProvider the {@link DnsServerAddressStreamProvider} which determines which DNS
* server should be used per query.
* @return {@code this}.
*/
public DefaultDnsServiceDiscovererBuilder dnsServerAddressStreamProvider(
@Nullable final DnsServerAddressStreamProvider dnsServerAddressStreamProvider) {
this.dnsServerAddressStreamProvider = dnsServerAddressStreamProvider;
return this;
}
/**
* Enable the automatic inclusion of a optional records that tries to give the remote DNS server a hint about
* how much data the resolver can read per response. Some DNSServer may not support this and so fail to answer
* queries. If you find problems you may want to disable this.
*
* @param optResourceEnabled if optional records inclusion is enabled.
* @return {@code this}.
*/
public DefaultDnsServiceDiscovererBuilder optResourceEnabled(final boolean optResourceEnabled) {
this.optResourceEnabled = optResourceEnabled;
return this;
}
/**
* Set the number of dots which must appear in a name before an initial absolute query is made.
*
* @param ndots the ndots value.
* @return {@code this}.
*/
public DefaultDnsServiceDiscovererBuilder ndots(final int ndots) {
this.ndots = ndots;
return this;
}
/**
* Sets the timeout of each DNS query performed by this service discoverer.
*
* @param queryTimeout the query timeout value
* @return {@code this}.
*/
public DefaultDnsServiceDiscovererBuilder queryTimeout(final Duration queryTimeout) {
this.queryTimeout = queryTimeout;
return this;
}
/**
* Allows sending 'unavailable' events for all current active hosts for particular DNS errors.
* <p>
* Note: The default does not send 'unavailable' events when a DNS lookup times out.
*
* @param invalidateHostsOnDnsFailure determines whether or not to send 'unavailable' events.
* @return {@code this}.
*/
public DefaultDnsServiceDiscovererBuilder invalidateHostsOnDnsFailure(
final Predicate<Throwable> invalidateHostsOnDnsFailure) {
this.invalidateHostsOnDnsFailure = invalidateHostsOnDnsFailure;
return this;
}
/**
* Returns a default value for {@link #invalidateHostsOnDnsFailure(Predicate)}.
*
* @return a default value for {@link #invalidateHostsOnDnsFailure(Predicate)}
*/
public static Predicate<Throwable> defaultInvalidateHostsOnDnsFailurePredicate() {
return t -> t instanceof UnknownHostException &&
!(t.getCause() instanceof DnsNameResolverTimeoutException);
}
/**
* Sets the list of the protocol families of the address resolved.
*
* @param dnsResolverAddressTypes the address types.
* @return {@code this}.
*/
public DefaultDnsServiceDiscovererBuilder dnsResolverAddressTypes(
@Nullable final DnsResolverAddressTypes dnsResolverAddressTypes) {
this.dnsResolverAddressTypes = dnsResolverAddressTypes;
return this;
}
/**
* Append the filter to the chain of filters used to decorate the {@link ServiceDiscoverer} created by this
* builder.
* <p>
* Note this method will be used to decorate the result of {@link #build()} before it is returned to the user.
* <p>
* The order of execution of these filters are in order of append. If 3 filters are added as follows:
* <pre>
* builder.append(filter1).append(filter2).append(filter3)
* </pre>
* making a request to a service discoverer wrapped by this filter chain the order of invocation of these filters
* will be:
* <pre>
* filter1 => filter2 => filter3 => service discoverer
* </pre>
*
* @param factory {@link DnsClientFilterFactory} to decorate a {@link DnsClient} for the purpose of
* filtering.
* @return {@code this}
*/
DefaultDnsServiceDiscovererBuilder appendFilter(final DnsClientFilterFactory factory) {
filterFactory = filterFactory == null ? requireNonNull(factory) : filterFactory.append(factory);
return this;
}
/**
* Sets the {@link IoExecutor}.
*
* @param ioExecutor {@link IoExecutor} to use.
* @return {@code this}.
*/
public DefaultDnsServiceDiscovererBuilder ioExecutor(final IoExecutor ioExecutor) {
this.ioExecutor = ioExecutor;
return this;
}
/**
* Sets a {@link DnsServiceDiscovererObserver} that provides visibility into
* <a href="https://tools.ietf.org/html/rfc1034">DNS</a> {@link ServiceDiscoverer} built by this builder.
*
* @param observer a {@link DnsServiceDiscovererObserver} that provides visibility into
* <a href="https://tools.ietf.org/html/rfc1034">DNS</a> {@link ServiceDiscoverer} built by this builder
* @return {@code this}.
*/
public DefaultDnsServiceDiscovererBuilder observer(final DnsServiceDiscovererObserver observer) {
this.observer = requireNonNull(observer);
return this;
}
/**
* Build a new {@link ServiceDiscoverer} which queries
* <a href="https://tools.ietf.org/html/rfc2782">SRV Resource Records</a> corresponding to {@code serviceName}. For
* each SRV answer capture the <strong>Port</strong> and resolve the <strong>Target</strong>.
* @return a new {@link ServiceDiscoverer} which queries
* <a href="https://tools.ietf.org/html/rfc2782">SRV Resource Records</a> corresponding to {@code serviceName}. For
* each SRV answer capture the <strong>Port</strong> and resolve the <strong>Target</strong>.
*/
public ServiceDiscoverer<String, InetSocketAddress, ServiceDiscovererEvent<InetSocketAddress>>
buildSrvDiscoverer() {
return asSrvDiscoverer(build());
}
/**
* Build a new {@link ServiceDiscoverer} which targets
* <a href="https://tools.ietf.org/html/rfc1035">host addresses</a> (e.g. A or AAAA records) and uses
* a fixed port derived from the {@link HostAndPort}.
* @return a new {@link ServiceDiscoverer} which targets
* <a href="https://tools.ietf.org/html/rfc1035">host addresses</a> (e.g. A or AAAA records) and uses
* a fixed port derived from the {@link HostAndPort}.
*/
public ServiceDiscoverer<HostAndPort, InetSocketAddress, ServiceDiscovererEvent<InetSocketAddress>>
buildARecordDiscoverer() {
return asHostAndPortDiscoverer(build());
}
/**
* Create a new instance of {@link DnsClient}.
*
* @return a new instance of {@link DnsClient}.
*/
DnsClient build() {
final DnsClient rawClient = new DefaultDnsClient(
ioExecutor == null ? globalExecutionContext().ioExecutor() : ioExecutor, minTTLSeconds, ndots,
invalidateHostsOnDnsFailure, optResourceEnabled, queryTimeout, dnsResolverAddressTypes,
dnsServerAddressStreamProvider, observer);
return filterFactory == null ? rawClient : filterFactory.create(rawClient);
}
}