Skip to content

Commit

Permalink
Enable DNS retryOnTimeout with TCP (#3063)
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 186c101
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 186c101

Please sign in to comment.