mirror of https://github.com/grpc/grpc-node.git
support selecting resolver via env
This commit is contained in:
parent
c3d073b0cc
commit
6278da6aec
|
|
@ -20,7 +20,6 @@ import {
|
||||||
registerResolver,
|
registerResolver,
|
||||||
registerDefaultScheme,
|
registerDefaultScheme,
|
||||||
} from './resolver';
|
} from './resolver';
|
||||||
import { AnyRecord } from 'dns';
|
|
||||||
import * as dns from 'dns/promises';
|
import * as dns from 'dns/promises';
|
||||||
import { extractAndSelectServiceConfig, ServiceConfig } from './service-config';
|
import { extractAndSelectServiceConfig, ServiceConfig } from './service-config';
|
||||||
import { Status } from './constants';
|
import { Status } from './constants';
|
||||||
|
|
@ -45,7 +44,8 @@ function trace(text: string): void {
|
||||||
*/
|
*/
|
||||||
export const DEFAULT_PORT = 443;
|
export const DEFAULT_PORT = 443;
|
||||||
|
|
||||||
const DEFAULT_MIN_TIME_BETWEEN_RESOLUTIONS_MS = 30_000;
|
const DEFAULT_MIN_TIME_BETWEEN_RESOLUTIONS_MS = 30_000,
|
||||||
|
DNS_RESOLUTION_ENV = 'GRPC_DNS_RESOLVER_TODO';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolver implementation that handles DNS names and IP addresses.
|
* Resolver implementation that handles DNS names and IP addresses.
|
||||||
|
|
@ -60,7 +60,7 @@ class DnsResolver implements Resolver {
|
||||||
* Failures are handled by the backoff timer.
|
* Failures are handled by the backoff timer.
|
||||||
*/
|
*/
|
||||||
private readonly minTimeBetweenResolutionsMs: number;
|
private readonly minTimeBetweenResolutionsMs: number;
|
||||||
private pendingLookupPromise: Promise<AnyRecord[]> | null = null;
|
private pendingLookupPromise: Promise<TcpSubchannelAddress[]> | null = null;
|
||||||
private pendingTxtPromise: Promise<string[][]> | null = null;
|
private pendingTxtPromise: Promise<string[][]> | null = null;
|
||||||
private latestLookupResult: Endpoint[] | null = null;
|
private latestLookupResult: Endpoint[] | null = null;
|
||||||
private latestServiceConfig: ServiceConfig | null = null;
|
private latestServiceConfig: ServiceConfig | null = null;
|
||||||
|
|
@ -73,7 +73,7 @@ class DnsResolver implements Resolver {
|
||||||
private isNextResolutionTimerRunning = false;
|
private isNextResolutionTimerRunning = false;
|
||||||
private isServiceConfigEnabled = true;
|
private isServiceConfigEnabled = true;
|
||||||
private returnedIpResult = false;
|
private returnedIpResult = false;
|
||||||
private resolver = new dns.Resolver();
|
private independentResolver = new dns.Resolver();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private target: GrpcUri,
|
private target: GrpcUri,
|
||||||
|
|
@ -82,7 +82,7 @@ class DnsResolver implements Resolver {
|
||||||
) {
|
) {
|
||||||
trace('Resolver constructed for target ' + uriToString(target));
|
trace('Resolver constructed for target ' + uriToString(target));
|
||||||
if (target.authority) {
|
if (target.authority) {
|
||||||
this.resolver.setServers([target.authority]);
|
this.independentResolver.setServers([target.authority]);
|
||||||
}
|
}
|
||||||
const hostPort = splitHostPort(target.path);
|
const hostPort = splitHostPort(target.path);
|
||||||
if (hostPort === null) {
|
if (hostPort === null) {
|
||||||
|
|
@ -187,11 +187,7 @@ class DnsResolver implements Resolver {
|
||||||
* revert to an effectively blank one. */
|
* revert to an effectively blank one. */
|
||||||
this.latestLookupResult = null;
|
this.latestLookupResult = null;
|
||||||
const hostname: string = this.dnsHostname;
|
const hostname: string = this.dnsHostname;
|
||||||
/* We lookup both address families here and then split them up later
|
this.pendingLookupPromise = this.lookup(hostname);
|
||||||
* because when looking up a single family, dns.lookup outputs an error
|
|
||||||
* if the name exists but there are no records for that family, and that
|
|
||||||
* error is indistinguishable from other kinds of errors */
|
|
||||||
this.pendingLookupPromise = this.resolver.resolveAny(hostname);
|
|
||||||
this.pendingLookupPromise.then(
|
this.pendingLookupPromise.then(
|
||||||
addressList => {
|
addressList => {
|
||||||
if (this.pendingLookupPromise === null) {
|
if (this.pendingLookupPromise === null) {
|
||||||
|
|
@ -200,19 +196,12 @@ class DnsResolver implements Resolver {
|
||||||
this.pendingLookupPromise = null;
|
this.pendingLookupPromise = null;
|
||||||
this.backoff.reset();
|
this.backoff.reset();
|
||||||
this.backoff.stop();
|
this.backoff.stop();
|
||||||
const subchannelAddresses: TcpSubchannelAddress[] = addressList
|
this.latestLookupResult = addressList.map(address => ({
|
||||||
.filter(addr => {
|
|
||||||
addr.type === 'A' || addr.type === 'AAAA';
|
|
||||||
})
|
|
||||||
.map(addr => ({ host: addr.address, port: +this.port! }));
|
|
||||||
this.latestLookupResult = subchannelAddresses.map(address => ({
|
|
||||||
addresses: [address],
|
addresses: [address],
|
||||||
}));
|
}));
|
||||||
const allAddressesString: string =
|
const allAddressesString: string =
|
||||||
'[' +
|
'[' +
|
||||||
subchannelAddresses
|
addressList.map(addr => addr.host + ':' + addr.port).join(',') +
|
||||||
.map(addr => addr.host + ':' + addr.port)
|
|
||||||
.join(',') +
|
|
||||||
']';
|
']';
|
||||||
trace(
|
trace(
|
||||||
'Resolved addresses for target ' +
|
'Resolved addresses for target ' +
|
||||||
|
|
@ -257,7 +246,7 @@ class DnsResolver implements Resolver {
|
||||||
/* We handle the TXT query promise differently than the others because
|
/* We handle the TXT query promise differently than the others because
|
||||||
* the name resolution attempt as a whole is a success even if the TXT
|
* the name resolution attempt as a whole is a success even if the TXT
|
||||||
* lookup fails */
|
* lookup fails */
|
||||||
this.pendingTxtPromise = this.resolver.resolveTxt(hostname);
|
this.pendingTxtPromise = this.resolveTxt(hostname);
|
||||||
this.pendingTxtPromise.then(
|
this.pendingTxtPromise.then(
|
||||||
txtRecord => {
|
txtRecord => {
|
||||||
if (this.pendingTxtPromise === null) {
|
if (this.pendingTxtPromise === null) {
|
||||||
|
|
@ -306,6 +295,35 @@ class DnsResolver implements Resolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async lookup(hostname: string): Promise<TcpSubchannelAddress[]> {
|
||||||
|
if (process.env[DNS_RESOLUTION_ENV] === 'true') {
|
||||||
|
const records = await this.independentResolver.resolveAny(hostname);
|
||||||
|
const addressList = records.filter(addr => {
|
||||||
|
addr.type === 'A' || addr.type === 'AAAA';
|
||||||
|
}) as unknown as { address: string }[];
|
||||||
|
|
||||||
|
return addressList.map(addr => ({
|
||||||
|
host: addr.address,
|
||||||
|
port: +this.port!,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We lookup both address families here and then split them up later
|
||||||
|
* because when looking up a single family, dns.lookup outputs an error
|
||||||
|
* if the name exists but there are no records for that family, and that
|
||||||
|
* error is indistinguishable from other kinds of errors */
|
||||||
|
const addressList = await dns.lookup(hostname, { all: true });
|
||||||
|
return addressList.map(addr => ({ host: addr.address, port: +this.port! }));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async resolveTxt(hostname: string): Promise<string[][]> {
|
||||||
|
if (process.env[DNS_RESOLUTION_ENV] === 'true') {
|
||||||
|
return this.independentResolver.resolveTxt(hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dns.resolveTxt(hostname);
|
||||||
|
}
|
||||||
|
|
||||||
private startNextResolutionTimer() {
|
private startNextResolutionTimer() {
|
||||||
clearTimeout(this.nextResolutionTimer);
|
clearTimeout(this.nextResolutionTimer);
|
||||||
this.nextResolutionTimer = setTimeout(() => {
|
this.nextResolutionTimer = setTimeout(() => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue