Skip to content

Commit 8a50303

Browse files
committed
grpc-js: Add support for grpc.dns_min_time_between_resolutions_ms channel arg
1 parent a993703 commit 8a50303

File tree

4 files changed

+43
-7
lines changed

4 files changed

+43
-7
lines changed

packages/grpc-js/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Many channel arguments supported in `grpc` are not supported in `@grpc/grpc-js`.
5858
- `grpc.enable_http_proxy`
5959
- `grpc.default_compression_algorithm`
6060
- `grpc.enable_channelz`
61+
- `grpc.dns_min_time_between_resolutions_ms`
6162
- `grpc-node.max_session_memory`
6263
- `channelOverride`
6364
- `channelFactoryOverride`

packages/grpc-js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@grpc/grpc-js",
3-
"version": "1.6.0",
3+
"version": "1.6.1",
44
"description": "gRPC Library for Node - pure JS implementation",
55
"homepage": "https://grpc.io/",
66
"repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js",

packages/grpc-js/src/channel-options.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export interface ChannelOptions {
4343
'grpc.http_connect_creds'?: string;
4444
'grpc.default_compression_algorithm'?: CompressionAlgorithms;
4545
'grpc.enable_channelz'?: number;
46+
'grpc.dns_min_time_between_resolutions_ms'?: number;
4647
'grpc-node.max_session_memory'?: number;
4748
// eslint-disable-next-line @typescript-eslint/no-explicit-any
4849
[key: string]: any;
@@ -69,6 +70,7 @@ export const recognizedOptions = {
6970
'grpc.max_receive_message_length': true,
7071
'grpc.enable_http_proxy': true,
7172
'grpc.enable_channelz': true,
73+
'grpc.dns_min_time_between_resolutions_ms': true,
7274
'grpc-node.max_session_memory': true,
7375
};
7476

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

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ function trace(text: string): void {
4545
*/
4646
const DEFAULT_PORT = 443;
4747

48+
const DEFAULT_MIN_TIME_BETWEEN_RESOLUTIONS_MS = 30_000;
49+
4850
const resolveTxtPromise = util.promisify(dns.resolveTxt);
4951
const dnsLookupPromise = util.promisify(dns.lookup);
5052

@@ -79,6 +81,12 @@ class DnsResolver implements Resolver {
7981
private readonly ipResult: SubchannelAddress[] | null;
8082
private readonly dnsHostname: string | null;
8183
private readonly port: number | null;
84+
/**
85+
* Minimum time between resolutions, measured as the time between starting
86+
* successive resolution requests. Only applies to successful resolutions.
87+
* Failures are handled by the backoff timer.
88+
*/
89+
private readonly minTimeBetweenResolutionsMs: number;
8290
private pendingLookupPromise: Promise<dns.LookupAddress[]> | null = null;
8391
private pendingTxtPromise: Promise<string[][]> | null = null;
8492
private latestLookupResult: TcpSubchannelAddress[] | null = null;
@@ -88,6 +96,8 @@ class DnsResolver implements Resolver {
8896
private defaultResolutionError: StatusObject;
8997
private backoff: BackoffTimeout;
9098
private continueResolving = false;
99+
private nextResolutionTimer: NodeJS.Timer;
100+
private isNextResolutionTimerRunning = false;
91101
constructor(
92102
private target: GrpcUri,
93103
private listener: ResolverListener,
@@ -134,6 +144,10 @@ class DnsResolver implements Resolver {
134144
}
135145
}, backoffOptions);
136146
this.backoff.unref();
147+
148+
this.minTimeBetweenResolutionsMs = channelOptions['grpc.dns_min_time_between_resolutions_ms'] ?? DEFAULT_MIN_TIME_BETWEEN_RESOLUTIONS_MS;
149+
this.nextResolutionTimer = setTimeout(() => {}, 0);
150+
clearTimeout(this.nextResolutionTimer);
137151
}
138152

139153
/**
@@ -183,6 +197,7 @@ class DnsResolver implements Resolver {
183197
(addressList) => {
184198
this.pendingLookupPromise = null;
185199
this.backoff.reset();
200+
this.backoff.stop();
186201
const ip4Addresses: dns.LookupAddress[] = addressList.filter(
187202
(addr) => addr.family === 4
188203
);
@@ -229,6 +244,7 @@ class DnsResolver implements Resolver {
229244
(err as Error).message
230245
);
231246
this.pendingLookupPromise = null;
247+
this.stopNextResolutionTimer();
232248
this.listener.onError(this.defaultResolutionError);
233249
}
234250
);
@@ -282,17 +298,34 @@ class DnsResolver implements Resolver {
282298
}
283299
}
284300

301+
private startNextResolutionTimer() {
302+
this.nextResolutionTimer = setTimeout(() => {
303+
this.stopNextResolutionTimer();
304+
if (this.continueResolving) {
305+
this.startResolutionWithBackoff();
306+
}
307+
}, this.minTimeBetweenResolutionsMs).unref?.();
308+
this.isNextResolutionTimerRunning = true;
309+
}
310+
311+
private stopNextResolutionTimer() {
312+
clearTimeout(this.nextResolutionTimer);
313+
this.isNextResolutionTimerRunning = false;
314+
}
315+
285316
private startResolutionWithBackoff() {
286317
this.startResolution();
287318
this.backoff.runOnce();
319+
this.startNextResolutionTimer();
288320
}
289321

290322
updateResolution() {
291323
/* If there is a pending lookup, just let it finish. Otherwise, if the
292-
* backoff timer is running, do another lookup when it ends, and if not,
293-
* do another lookup immeidately. */
324+
* nextResolutionTimer or backoff timer is running, set the
325+
* continueResolving flag to resolve when whichever of those timers
326+
* fires. Otherwise, start resolving immediately. */
294327
if (this.pendingLookupPromise === null) {
295-
if (this.backoff.isRunning()) {
328+
if (this.isNextResolutionTimerRunning || this.backoff.isRunning()) {
296329
this.continueResolving = true;
297330
} else {
298331
this.startResolutionWithBackoff();
@@ -301,9 +334,9 @@ class DnsResolver implements Resolver {
301334
}
302335

303336
destroy() {
304-
/* Do nothing. There is not a practical way to cancel in-flight DNS
305-
* requests, and after this function is called we can expect that
306-
* updateResolution will not be called again. */
337+
this.continueResolving = false;
338+
this.backoff.stop();
339+
this.stopNextResolutionTimer();
307340
}
308341

309342
/**

0 commit comments

Comments
 (0)