Skip to content

Commit ee7fbdd

Browse files
committed
Split overall and individual server timeouts in ExtendedResolver
1 parent d244bf4 commit ee7fbdd

1 file changed

Lines changed: 48 additions & 22 deletions

File tree

src/main/java/org/xbill/DNS/ExtendedResolver.java

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
package org.xbill.DNS;
44

5+
import java.io.IOException;
56
import java.net.InetSocketAddress;
67
import java.net.UnknownHostException;
78
import java.time.Duration;
@@ -34,9 +35,11 @@ private static class Resolution {
3435
private final int retriesPerResolver;
3536
private List<ResolverEntry> resolvers;
3637
private int currentResolver;
38+
private long endTime;
3739

3840
Resolution(ExtendedResolver eres, Message query) {
3941
resolvers = new ArrayList<>(eres.resolvers);
42+
endTime = System.nanoTime() + eres.timeout.toNanos();
4043
if (eres.loadBalance) {
4144
int start = eres.lbStart.updateAndGet(i -> i++ % resolvers.size());
4245
if (start > 0) {
@@ -99,14 +102,26 @@ private Void handle(Message result, Throwable ex, CompletableFuture<Message> f)
99102
ex.getMessage());
100103

101104
failureCounter.incrementAndGet();
102-
// go to next resolver, until retries on all resolvers are exhausted
103-
currentResolver = (currentResolver + 1) % resolvers.size();
104-
if (attempts[currentResolver] < retriesPerResolver) {
105-
send().handleAsync((r, t) -> handle(r, t, f));
106-
return null;
107-
}
108105

109-
f.completeExceptionally(ex);
106+
if (endTime - System.nanoTime() < 0) {
107+
f.completeExceptionally(
108+
new IOException(
109+
"Timed out while trying to resolve "
110+
+ query.getQuestion().getName()
111+
+ "/"
112+
+ Type.string(query.getQuestion().type)
113+
+ ", id="
114+
+ query.getHeader().getID()));
115+
} else {
116+
// go to next resolver, until retries on all resolvers are exhausted
117+
currentResolver = (currentResolver + 1) % resolvers.size();
118+
if (attempts[currentResolver] < retriesPerResolver) {
119+
send().handleAsync((r, t) -> handle(r, t, f));
120+
return null;
121+
}
122+
123+
f.completeExceptionally(ex);
124+
}
110125
} else {
111126
failureCounter.updateAndGet(i -> i > 0 ? (int) Math.log(i) : 0);
112127
f.complete(result);
@@ -136,16 +151,25 @@ public String toString() {
136151
*
137152
* @since 3.2
138153
*/
139-
public static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(5);
154+
public static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(10);
155+
156+
/**
157+
* Default timeout until resolving with one of the used resolvers fails.
158+
*
159+
* @since 3.2
160+
*/
161+
public static final Duration DEFAULT_RESOLVER_TIMEOUT = Duration.ofSeconds(5);
140162

141163
private final List<ResolverEntry> resolvers = new CopyOnWriteArrayList<>();
142-
private boolean loadBalance;
143164
private final AtomicInteger lbStart = new AtomicInteger();
165+
private boolean loadBalance;
144166
private int retries = 3;
167+
private Duration timeout = DEFAULT_TIMEOUT;
145168

146169
/**
147170
* Creates a new Extended Resolver. The default {@link ResolverConfig} is used to determine the
148-
* servers for which {@link SimpleResolver}s are initialized.
171+
* servers for which {@link SimpleResolver}s are initialized. The timeout for each server is
172+
* initialized with {@link #DEFAULT_RESOLVER_TIMEOUT}.
149173
*/
150174
public ExtendedResolver() {
151175
List<InetSocketAddress> servers = ResolverConfig.getCurrentConfig().servers();
@@ -154,14 +178,15 @@ public ExtendedResolver() {
154178
.map(
155179
server -> {
156180
Resolver r = new SimpleResolver(server);
157-
r.setTimeout(DEFAULT_TIMEOUT);
181+
r.setTimeout(DEFAULT_RESOLVER_TIMEOUT);
158182
return new ResolverEntry(r);
159183
})
160184
.collect(Collectors.toSet()));
161185
}
162186

163187
/**
164-
* Creates a new Extended Resolver
188+
* Creates a new instance with {@link SimpleResolver}s. The timeout for each server is initialized
189+
* with {@link #DEFAULT_RESOLVER_TIMEOUT}.
165190
*
166191
* @param servers An array of server names or IP addresses for which {@link SimpleResolver}s are
167192
* initialized.
@@ -175,7 +200,7 @@ public ExtendedResolver(String[] servers) throws UnknownHostException {
175200
server -> {
176201
try {
177202
Resolver r = new SimpleResolver(server);
178-
r.setTimeout(DEFAULT_TIMEOUT);
203+
r.setTimeout(DEFAULT_RESOLVER_TIMEOUT);
179204
return new ResolverEntry(r);
180205
} catch (UnknownHostException e) {
181206
throw new RuntimeException(e);
@@ -200,18 +225,16 @@ public ExtendedResolver(Resolver[] resolvers) {
200225
}
201226

202227
/**
203-
* Creates a new Extended Resolver
228+
* Creates a new {@link ExtendedResolver}. No timeout value is applied to the individual
229+
* resolvers, make sure their timeout is smaller than the timeout of this {@link
230+
* ExtendedResolver}.
204231
*
205232
* @param resolvers An iterable of pre-initialized {@link Resolver}s.
206233
*/
207234
public ExtendedResolver(Iterable<Resolver> resolvers) {
208235
this.resolvers.addAll(
209236
StreamSupport.stream(resolvers.spliterator(), false)
210-
.map(
211-
resolver -> {
212-
resolver.setTimeout(DEFAULT_TIMEOUT);
213-
return new ResolverEntry(resolver);
214-
})
237+
.map(ResolverEntry::new)
215238
.collect(Collectors.toSet()));
216239
}
217240

@@ -250,11 +273,14 @@ public void setTSIGKey(TSIG key) {
250273
}
251274
}
252275

276+
@Override
277+
public Duration getTimeout() {
278+
return timeout;
279+
}
280+
253281
@Override
254282
public void setTimeout(Duration timeout) {
255-
for (ResolverEntry re : resolvers) {
256-
re.resolver.setTimeout(timeout);
257-
}
283+
this.timeout = timeout;
258284
}
259285

260286
/**

0 commit comments

Comments
 (0)