Skip to content

Commit 5a728ff

Browse files
committed
grpc-js: Add backoff to DNS resolution attempts
1 parent 37b9ec6 commit 5a728ff

File tree

1 file changed

+31
-2
lines changed

1 file changed

+31
-2
lines changed

packages/grpc-js/src/resolver-dns.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { SubchannelAddress, TcpSubchannelAddress } from './subchannel-address';
3232
import { GrpcUri, uriToString, splitHostPort } from './uri-parser';
3333
import { isIPv6, isIPv4 } from 'net';
3434
import { ChannelOptions } from './channel-options';
35+
import { BackoffOptions, BackoffTimeout } from './backoff-timeout';
3536

3637
const TRACER_NAME = 'dns_resolver';
3738

@@ -85,6 +86,8 @@ class DnsResolver implements Resolver {
8586
private latestServiceConfigError: StatusObject | null = null;
8687
private percentage: number;
8788
private defaultResolutionError: StatusObject;
89+
private backoff: BackoffTimeout;
90+
private continueResolving = false;
8891
constructor(
8992
private target: GrpcUri,
9093
private listener: ResolverListener,
@@ -119,6 +122,18 @@ class DnsResolver implements Resolver {
119122
details: `Name resolution failed for target ${uriToString(this.target)}`,
120123
metadata: new Metadata(),
121124
};
125+
126+
const backoffOptions: BackoffOptions = {
127+
initialDelay: channelOptions['grpc.initial_reconnect_backoff_ms'],
128+
maxDelay: channelOptions['grpc.max_reconnect_backoff_ms'],
129+
};
130+
131+
this.backoff = new BackoffTimeout(() => {
132+
if (this.continueResolving) {
133+
this.startResolutionWithBackoff();
134+
}
135+
}, backoffOptions);
136+
this.backoff.unref();
122137
}
123138

124139
/**
@@ -140,6 +155,7 @@ class DnsResolver implements Resolver {
140155
return;
141156
}
142157
if (this.dnsHostname === null) {
158+
trace('Failed to parse DNS address ' + uriToString(this.target));
143159
setImmediate(() => {
144160
this.listener.onError({
145161
code: Status.UNAVAILABLE,
@@ -148,6 +164,7 @@ class DnsResolver implements Resolver {
148164
});
149165
});
150166
} else {
167+
trace('Looking up DNS hostname ' + this.dnsHostname);
151168
/* We clear out latestLookupResult here to ensure that it contains the
152169
* latest result since the last time we started resolving. That way, the
153170
* TXT resolution handler can use it, but only if it finishes second. We
@@ -164,6 +181,7 @@ class DnsResolver implements Resolver {
164181
this.pendingLookupPromise.then(
165182
(addressList) => {
166183
this.pendingLookupPromise = null;
184+
this.backoff.reset();
167185
const ip4Addresses: dns.LookupAddress[] = addressList.filter(
168186
(addr) => addr.family === 4
169187
);
@@ -263,10 +281,21 @@ class DnsResolver implements Resolver {
263281
}
264282
}
265283

284+
private startResolutionWithBackoff() {
285+
this.startResolution();
286+
this.backoff.runOnce();
287+
}
288+
266289
updateResolution() {
267-
trace('Resolution update requested for target ' + uriToString(this.target));
290+
/* If there is a pending lookup, just let it finish. Otherwise, if the
291+
* backoff timer is running, do another lookup when it ends, and if not,
292+
* do another lookup immeidately. */
268293
if (this.pendingLookupPromise === null) {
269-
this.startResolution();
294+
if (this.backoff.isRunning()) {
295+
this.continueResolving = true;
296+
} else {
297+
this.startResolutionWithBackoff();
298+
}
270299
}
271300
}
272301

0 commit comments

Comments
 (0)