@@ -147,112 +147,6 @@ final class DefaultDnsClient implements DnsClient {
147147 private final String id ;
148148 private boolean closed ;
149149
150- private interface DnsNameResolverDelegate {
151- void close ();
152-
153- Future <List <InetAddress >> resolveAll (String name );
154-
155- Future <List <DnsRecord >> resolveAll (DnsQuestion name );
156-
157- long queryTimeoutMillis ();
158- }
159-
160- private static final class SingleResolver implements DnsNameResolverDelegate {
161- private final DnsNameResolver nettyResolver ;
162-
163- SingleResolver (DnsNameResolver nettyResolver ) {
164- this .nettyResolver = nettyResolver ;
165- }
166-
167- @ Override
168- public void close () {
169- nettyResolver .close ();
170- }
171-
172- @ Override
173- public Future <List <InetAddress >> resolveAll (String name ) {
174- return nettyResolver .resolveAll (name );
175- }
176-
177- @ Override
178- public Future <List <DnsRecord >> resolveAll (DnsQuestion question ) {
179- return nettyResolver .resolveAll (question );
180- }
181-
182- @ Override
183- public long queryTimeoutMillis () {
184- return nettyResolver .queryTimeoutMillis ();
185- }
186- }
187-
188- private static final class BackupRequestResolver implements DnsNameResolverDelegate {
189-
190- private final DnsNameResolver primaryResolver ;
191- private final DnsNameResolver backupResolver ;
192- private final EventLoop eventLoop ;
193-
194- // TODO: we'll want to make sure we share the cache, make our backup request interval more flexible, and also
195- // give ourselves some sort of budget so we don't overload DNS, but these are all possible.
196- BackupRequestResolver (DnsNameResolverBuilder builder , EventLoop eventLoop ) {
197- primaryResolver = builder .build ();
198- backupResolver = builder .consolidateCacheSize (0 ).build ();
199- this .eventLoop = eventLoop ;
200- }
201-
202- @ Override
203- public void close () {
204- try {
205- primaryResolver .close ();
206- } finally {
207- backupResolver .close ();
208- }
209- }
210-
211- @ Override
212- public Future <List <InetAddress >> resolveAll (String name ) {
213- return withBackup (resolver -> resolver .resolveAll (name ));
214- }
215-
216- @ Override
217- public Future <List <DnsRecord >> resolveAll (DnsQuestion name ) {
218- return withBackup (resolver -> resolver .resolveAll (name ));
219- }
220-
221- @ Override
222- public long queryTimeoutMillis () {
223- return primaryResolver .queryTimeoutMillis ();
224- }
225-
226- private <T > Future <T > withBackup (Function <? super DnsNameResolver , ? extends Future <T >> query ) {
227- Future <T > primaryQuery = query .apply (primaryResolver );
228- if (primaryQuery .isDone ()) {
229- return primaryQuery ;
230- }
231- int backupDelay = backupDelayMs ();
232- if (backupDelay <= 0 ) {
233- // no backup for this request
234- return primaryQuery ;
235- }
236- Promise <T > result = eventLoop .newPromise ();
237- Future <?> timer = eventLoop .schedule (() -> {
238- if (allowBackupRequest ()) {
239- PromiseNotifier .cascade (false , query .apply (backupResolver ), result );
240- }
241- }, backupDelay , MILLISECONDS );
242- primaryQuery .addListener (_unused -> timer .cancel (true ));
243- PromiseNotifier .cascade (false , primaryQuery , result );
244- return result ;
245- }
246-
247- private boolean allowBackupRequest () {
248- return true ;
249- }
250-
251- private int backupDelayMs () {
252- return 50 ;
253- }
254- }
255-
256150 DefaultDnsClient (final String id , final IoExecutor ioExecutor , final int consolidateCacheSize ,
257151 final int minTTL , final int maxTTL , final int minCacheTTL , final int maxCacheTTL ,
258152 final int negativeTTLCacheSeconds , final long ttlJitterNanos ,
@@ -269,7 +163,8 @@ private int backupDelayMs() {
269163 final ServiceDiscovererEvent .Status missingRecordStatus ,
270164 final boolean nxInvalidation ,
271165 final boolean tcpFallbackOnTimeout ,
272- final String datagramChannelStrategy ) {
166+ final String datagramChannelStrategy ,
167+ @ Nullable final Integer backupRequestDelay ) {
273168 this .srvConcurrency = srvConcurrency ;
274169 this .srvFilterDuplicateEvents = srvFilterDuplicateEvents ;
275170 // Implementation of this class expects to use only single EventLoop from IoExecutor
@@ -338,8 +233,9 @@ private int backupDelayMs() {
338233 if (dnsServerAddressStreamProvider != null ) {
339234 builder .nameServerProvider (toNettyType (dnsServerAddressStreamProvider ));
340235 }
341- // resolver = new SingleResolver(builder.build());
342- resolver = new BackupRequestResolver (builder , eventLoop );
236+ resolver = backupRequestDelay == null || backupRequestDelay <= 0 ? new DefaultResolver (builder .build ()) :
237+ new BackupRequestResolver (builder .build (), builder .consolidateCacheSize (0 ).build (),
238+ eventLoop , backupRequestDelay );
343239 this .resolutionTimeoutMillis = resolutionTimeout != null ? resolutionTimeout .toMillis () :
344240 // Default value is chosen based on a combination of default "timeout" and "attempts" options of
345241 // /etc/resolv.conf: https://man7.org/linux/man-pages/man5/resolv.conf.5.html
@@ -1259,4 +1155,111 @@ static SrvAddressRemovedException newInstance(Class<?> clazz, String method) {
12591155 return unknownStackTrace (new SrvAddressRemovedException (), clazz , method );
12601156 }
12611157 }
1158+
1159+ interface DnsNameResolverDelegate {
1160+ void close ();
1161+
1162+ Future <List <InetAddress >> resolveAll (String name );
1163+
1164+ Future <List <DnsRecord >> resolveAll (DnsQuestion name );
1165+
1166+ long queryTimeoutMillis ();
1167+ }
1168+
1169+ static final class DefaultResolver implements DnsNameResolverDelegate {
1170+ private final DnsNameResolver nettyResolver ;
1171+
1172+ DefaultResolver (DnsNameResolver nettyResolver ) {
1173+ this .nettyResolver = nettyResolver ;
1174+ }
1175+
1176+ @ Override
1177+ public void close () {
1178+ nettyResolver .close ();
1179+ }
1180+
1181+ @ Override
1182+ public Future <List <InetAddress >> resolveAll (String name ) {
1183+ return nettyResolver .resolveAll (name );
1184+ }
1185+
1186+ @ Override
1187+ public Future <List <DnsRecord >> resolveAll (DnsQuestion question ) {
1188+ return nettyResolver .resolveAll (question );
1189+ }
1190+
1191+ @ Override
1192+ public long queryTimeoutMillis () {
1193+ return nettyResolver .queryTimeoutMillis ();
1194+ }
1195+ }
1196+
1197+ static final class BackupRequestResolver implements DnsNameResolverDelegate {
1198+
1199+ private final DnsNameResolver primaryResolver ;
1200+ private final DnsNameResolver backupResolver ;
1201+ private final EventLoop eventLoop ;
1202+ private final int backupDelayMs ;
1203+
1204+ BackupRequestResolver (DnsNameResolver primaryResolver , DnsNameResolver backupResolver , EventLoop eventLoop , int backupDelayMs ) {
1205+ this .primaryResolver = primaryResolver ;
1206+ this .backupResolver = backupResolver ;
1207+ this .eventLoop = eventLoop ;
1208+ this .backupDelayMs = backupDelayMs ;
1209+ }
1210+
1211+ @ Override
1212+ public void close () {
1213+ try {
1214+ primaryResolver .close ();
1215+ } finally {
1216+ backupResolver .close ();
1217+ }
1218+ }
1219+
1220+ @ Override
1221+ public Future <List <InetAddress >> resolveAll (String name ) {
1222+ return withBackup (resolver -> resolver .resolveAll (name ));
1223+ }
1224+
1225+ @ Override
1226+ public Future <List <DnsRecord >> resolveAll (DnsQuestion name ) {
1227+ return withBackup (resolver -> resolver .resolveAll (name ));
1228+ }
1229+
1230+ @ Override
1231+ public long queryTimeoutMillis () {
1232+ return primaryResolver .queryTimeoutMillis ();
1233+ }
1234+
1235+ private <T > Future <T > withBackup (Function <? super DnsNameResolver , ? extends Future <T >> query ) {
1236+ Future <T > primaryQuery = query .apply (primaryResolver );
1237+ if (primaryQuery .isDone ()) {
1238+ return primaryQuery ;
1239+ }
1240+ int backupDelay = backupDelayMs ();
1241+ if (backupDelay <= 0 ) {
1242+ // no backup for this request
1243+ return primaryQuery ;
1244+ }
1245+ Promise <T > result = eventLoop .newPromise ();
1246+ Future <?> timer = eventLoop .schedule (() -> {
1247+ if (allowBackupRequest ()) {
1248+ PromiseNotifier .cascade (false , query .apply (backupResolver ), result );
1249+ }
1250+ }, backupDelay , MILLISECONDS );
1251+ primaryQuery .addListener (_unused -> timer .cancel (true ));
1252+ PromiseNotifier .cascade (false , primaryQuery , result );
1253+ return result ;
1254+ }
1255+
1256+ private boolean allowBackupRequest () {
1257+ // In the future we should make this predicated on a token bucket.
1258+ return true ;
1259+ }
1260+
1261+ private int backupDelayMs () {
1262+ return backupDelayMs ;
1263+ }
1264+ }
12621265}
0 commit comments