Skip to content

Commit

Permalink
Enable DNS retryOnTimeout with TCP
Browse files Browse the repository at this point in the history
Add an API for configuring the resolver to fallback to TCP if a timeout is detected.
By default, the resolver will only try to use TCP if the response is marked as truncated.

Fixes #3059
  • Loading branch information
violetagg committed Feb 16, 2024
1 parent c2cf287 commit d895b83
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 2 deletions.
2 changes: 2 additions & 0 deletions docs/asciidoc/http-client.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,8 @@ Default: -1 (to determine the value from the OS on Unix or use a value of 1 othe
| `queryTimeout` | Sets the timeout of each DNS query performed by this resolver (resolution: milliseconds). Default: 5000.
| `resolveCache` | The cache to use to store resolved DNS entries.
| `resolvedAddressTypes` | The list of the protocol families of the resolved address.
| `retryTcpOnTimeout` | Specifies whether this resolver will also fallback to TCP if a timeout is detected.
By default, the resolver will only try to use TCP if the response is marked as truncated.
| `roundRobinSelection` | Enables an
{nettyjavadoc}/io/netty/resolver/AddressResolverGroup.html[`AddressResolverGroup`] of
{nettyjavadoc}/io/netty/resolver/dns/DnsNameResolver.html[`DnsNameResolver`] that supports random selection
Expand Down
2 changes: 2 additions & 0 deletions docs/asciidoc/tcp-client.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ Default: {nettyjavadoc}/io/netty/resolver/DefaultHostsFileEntriesResolver.html[`
| `queryTimeout` | Sets the timeout of each DNS query performed by this resolver (resolution: milliseconds). Default: 5000.
| `resolveCache` | The cache to use to store resolved DNS entries.
| `resolvedAddressTypes` | The list of the protocol families of the resolved address.
| `retryTcpOnTimeout` | Specifies whether this resolver will also fallback to TCP if a timeout is detected.
By default, the resolver will only try to use TCP if the response is marked as truncated.
| `roundRobinSelection` | Enables an
{nettyjavadoc}/io/netty/resolver/AddressResolverGroup.html[`AddressResolverGroup`] of
{nettyjavadoc}/io/netty/resolver/dns/DnsNameResolver.html[`DnsNameResolver`] that supports random selection
Expand Down
4 changes: 3 additions & 1 deletion reactor-netty-core/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2023 VMware, Inc. or its affiliates, All Rights Reserved.
* Copyright (c) 2020-2024 VMware, Inc. or its affiliates, All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -240,6 +240,8 @@ task japicmp(type: JapicmpTask) {
compatibilityChangeExcludes = [ "METHOD_NEW_DEFAULT" ]

methodExcludes = [
'reactor.netty.transport.NameResolverProvider#retryTcpOnTimeout()',
'reactor.netty.transport.NameResolverProvider$NameResolverSpec#retryTcpOnTimeout(boolean)'
]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,17 @@ NameResolverSpec dnsAddressResolverGroupProvider(
*/
NameResolverSpec resolvedAddressTypes(ResolvedAddressTypes resolvedAddressTypes);

/**
* Specifies whether this resolver will also fallback to TCP if a timeout is detected.
* By default, the resolver will only try to use TCP if the response is marked as truncated.
*
* @param enable if true this resolver will also fallback to TCP if a timeout is detected,
* if false the resolver will only try to use TCP if the response is marked as truncated.
* @return {@code this}
* @since 1.1.17
*/
NameResolverSpec retryTcpOnTimeout(boolean enable);

/**
* Enables an {@link AddressResolverGroup} of {@link DnsNameResolver}s that supports random selection
* of destination addresses if multiple are provided by the nameserver.
Expand Down Expand Up @@ -378,6 +389,16 @@ public boolean isPreferNative() {
return preferNative;
}

/**
* Returns {@code true} if the resolver will also fallback to TCP if a timeout is detected.
*
* @return {@code true} if the resolver will also fallback to TCP if a timeout is detected
* @since 1.1.17
*/
public boolean isRetryTcpOnTimeout() {
return retryTcpOnTimeout;
}

/**
* Returns true if {@link RoundRobinDnsAddressResolverGroup} is in use.
*
Expand Down Expand Up @@ -491,6 +512,7 @@ public boolean equals(Object o) {
queryTimeout.equals(that.queryTimeout) &&
Objects.equals(resolveCache, that.resolveCache) &&
resolvedAddressTypes == that.resolvedAddressTypes &&
retryTcpOnTimeout == that.retryTcpOnTimeout &&
roundRobinSelection == that.roundRobinSelection &&
// searchDomains is List so Objects.equals is OK
Objects.equals(searchDomains, that.searchDomains);
Expand All @@ -516,6 +538,7 @@ public int hashCode() {
result = 31 * result + Objects.hashCode(queryTimeout);
result = 31 * result + Objects.hashCode(resolveCache);
result = 31 * result + Objects.hashCode(resolvedAddressTypes);
result = 31 * result + Boolean.hashCode(retryTcpOnTimeout);
result = 31 * result + Boolean.hashCode(roundRobinSelection);
result = 31 * result + Objects.hashCode(searchDomains);
return result;
Expand Down Expand Up @@ -551,7 +574,7 @@ public DnsAddressResolverGroup newNameResolverGroup(LoopResources defaultLoopRes
.queryTimeoutMillis(queryTimeout.toMillis())
.eventLoop(group.next())
.channelFactory(() -> loop.onChannel(DatagramChannel.class, group))
.socketChannelFactory(() -> loop.onChannel(SocketChannel.class, group));
.socketChannelFactory(() -> loop.onChannel(SocketChannel.class, group), retryTcpOnTimeout);
if (bindAddressSupplier != null) {
// There is no check for bindAddressSupplier.get() == null
// This is deliberate, when null value is provided Netty will use the default behaviour
Expand Down Expand Up @@ -596,6 +619,7 @@ public DnsAddressResolverGroup newNameResolverGroup(LoopResources defaultLoopRes
final Duration queryTimeout;
final DnsCache resolveCache;
final ResolvedAddressTypes resolvedAddressTypes;
final boolean retryTcpOnTimeout;
final boolean roundRobinSelection;
final Iterable<String> searchDomains;

Expand All @@ -618,6 +642,7 @@ public DnsAddressResolverGroup newNameResolverGroup(LoopResources defaultLoopRes
this.queryTimeout = build.queryTimeout;
this.resolveCache = build.resolveCache;
this.resolvedAddressTypes = build.resolvedAddressTypes;
this.retryTcpOnTimeout = build.retryTcpOnTimeout;
this.roundRobinSelection = build.roundRobinSelection;
this.searchDomains = build.searchDomains;
}
Expand Down Expand Up @@ -650,6 +675,7 @@ static final class Build implements NameResolverSpec {
Duration queryTimeout = DEFAULT_QUERY_TIMEOUT;
DnsCache resolveCache;
ResolvedAddressTypes resolvedAddressTypes;
boolean retryTcpOnTimeout;
boolean roundRobinSelection;
Iterable<String> searchDomains;

Expand Down Expand Up @@ -755,6 +781,12 @@ public NameResolverSpec resolvedAddressTypes(ResolvedAddressTypes resolvedAddres
return this;
}

@Override
public NameResolverSpec retryTcpOnTimeout(boolean enable) {
this.retryTcpOnTimeout = enable;
return this;
}

@Override
public NameResolverSpec roundRobinSelection(boolean enable) {
this.roundRobinSelection = enable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,14 @@ void resolvedAddressTypesBadValues() {
.isThrownBy(() -> builder.resolvedAddressTypes(null));
}

@Test
void retryTcpOnTimeout() {
assertThat(builder.build().isRetryTcpOnTimeout()).isFalse();

builder.retryTcpOnTimeout(true);
assertThat(builder.build().isRetryTcpOnTimeout()).isTrue();
}

@Test
void roundRobinSelection() {
assertThat(builder.build().isRoundRobinSelection()).isFalse();
Expand Down

0 comments on commit d895b83

Please sign in to comment.