From bf1b078816c71bf44318eb60bd07ca18f165b488 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 14 Apr 2021 14:58:36 -0700 Subject: [PATCH 01/13] grpc-js: Update versions and xDS feature list --- packages/grpc-js-xds/README.md | 3 ++- packages/grpc-js-xds/package.json | 4 ++-- packages/grpc-js/package.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/README.md b/packages/grpc-js-xds/README.md index 2ada0bad..bcea7045 100644 --- a/packages/grpc-js-xds/README.md +++ b/packages/grpc-js-xds/README.md @@ -21,4 +21,5 @@ const client = new MyServiceClient('xds:///example.com:123'); ## Supported Features - - [xDS-Based Global Load Balancing](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) \ No newline at end of file + - [xDS-Based Global Load Balancing](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) + - [xDS traffic splitting and routing](https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md) \ No newline at end of file diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 3f90c7e9..f4f8d604 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.2.4", + "version": "1.3.0", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { @@ -47,7 +47,7 @@ "re2-wasm": "^1.0.1" }, "peerDependencies": { - "@grpc/grpc-js": "~1.2.10" + "@grpc/grpc-js": "~1.3.0" }, "engines": { "node": ">=10.10.0" diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 6a027d39..04fa4585 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.12", + "version": "1.3.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From c9aad43358983a560613e3f99412000df99aa526 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 16 Apr 2021 13:34:59 -0700 Subject: [PATCH 02/13] grpc-js: Add support for ipv4 and ipv6 schemes --- packages/grpc-js/src/resolver-ip.ts | 107 +++++++++++++++ packages/grpc-js/src/resolver.ts | 2 + packages/grpc-js/test/test-resolver.ts | 180 +++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 packages/grpc-js/src/resolver-ip.ts diff --git a/packages/grpc-js/src/resolver-ip.ts b/packages/grpc-js/src/resolver-ip.ts new file mode 100644 index 00000000..5c9e29c4 --- /dev/null +++ b/packages/grpc-js/src/resolver-ip.ts @@ -0,0 +1,107 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { isIPv4, isIPv6 } from "net"; +import { StatusObject } from "./call-stream"; +import { ChannelOptions } from "./channel-options"; +import { LogVerbosity, Status } from "./constants"; +import { Metadata } from "./metadata"; +import { registerResolver, Resolver, ResolverListener } from "./resolver"; +import { SubchannelAddress } from "./subchannel"; +import { GrpcUri, splitHostPort, uriToString } from "./uri-parser"; +import * as logging from './logging'; + +const TRACER_NAME = 'ip_resolver'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} + +const IPV4_SCHEME = 'ipv4'; +const IPV6_SCHEME = 'ipv6'; + +/** + * The default TCP port to connect to if not explicitly specified in the target. + */ +const DEFAULT_PORT = 443; + +class IpResolver implements Resolver { + private addresses: SubchannelAddress[] = []; + private error: StatusObject | null = null; + constructor( + private target: GrpcUri, + private listener: ResolverListener, + channelOptions: ChannelOptions + ) { + trace('Resolver constructed for target ' + uriToString(target)); + const addresses: SubchannelAddress[] = []; + if (!(target.scheme === IPV4_SCHEME || target.scheme === IPV6_SCHEME)) { + this.error = { + code: Status.UNAVAILABLE, + details: `Unrecognized scheme ${target.scheme} in IP resolver`, + metadata: new Metadata() + }; + return; + } + const pathList = target.path.split(','); + for (const path of pathList) { + const hostPort = splitHostPort(path); + if (hostPort === null) { + this.error = { + code: Status.UNAVAILABLE, + details: `Failed to parse ${target.scheme} address ${path}`, + metadata: new Metadata() + }; + return; + } + if ((target.scheme === IPV4_SCHEME && !isIPv4(hostPort.host)) || (target.scheme === IPV6_SCHEME && !isIPv6(hostPort.host))) { + this.error = { + code: Status.UNAVAILABLE, + details: `Failed to parse ${target.scheme} address ${path}`, + metadata: new Metadata() + }; + return; + } + addresses.push({ + host: hostPort.host, + port: hostPort.port ?? DEFAULT_PORT + }); + } + this.addresses = addresses; + trace('Parsed ' + target.scheme + ' address list ' + this.addresses); + } + updateResolution(): void { + process.nextTick(() => { + if (this.error) { + this.listener.onError(this.error) + } else { + this.listener.onSuccessfulResolution(this.addresses, null, null, null, {}); + } + }); + } + destroy(): void { + // This resolver owns no resources, so we do nothing here. + } + + static getDefaultAuthority(target: GrpcUri): string { + return target.path.split(',')[0]; + } +} + +export function setup() { + registerResolver(IPV4_SCHEME, IpResolver); + registerResolver(IPV6_SCHEME, IpResolver); +} \ No newline at end of file diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 147ace30..497f3dfa 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -18,6 +18,7 @@ import { MethodConfig, ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; +import * as resolver_ip from './resolver-ip'; import { StatusObject } from './call-stream'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; @@ -179,4 +180,5 @@ export function mapUriDefaultScheme(target: GrpcUri): GrpcUri | null { export function registerAll() { resolver_dns.setup(); resolver_uds.setup(); + resolver_ip.setup(); } diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index c4f42f6e..756d234c 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -388,6 +388,186 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); }); + describe('IP Addresses', () => { + it('should handle one IPv4 address with no port', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv4:127.0.0.1')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 443 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + it('should handle one IPv4 address with a port', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv4:127.0.0.1:50051')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 50051 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + it('should handle multiple IPv4 addresses with different ports', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv4:127.0.0.1:50051,127.0.0.1:50052')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 50051 + ) + ); + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 50052 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + it('should handle one IPv6 address with no port', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv6:::1')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 443 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + it('should handle one IPv6 address with a port', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv6:[::1]:50051')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 50051 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + it('should handle multiple IPv6 addresses with different ports', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv6:[::1]:50051,[::1]:50052')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 50051 + ) + ); + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 50052 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + }); describe('getDefaultAuthority', () => { class OtherResolver implements resolverManager.Resolver { updateResolution() { From 076aeccfdc88fbf24e8c8f65741803e231a41a00 Mon Sep 17 00:00:00 2001 From: Sahebjot singh Date: Wed, 21 Apr 2021 09:01:42 +0530 Subject: [PATCH 03/13] grpc-js: stricter function check than instanceof instanceof does not work in vm context --- packages/grpc-js/src/client.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 5f78ffe5..2f995e82 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -198,9 +198,9 @@ export class Client { options: CallOptions; callback: UnaryCallback; } { - if (arg1 instanceof Function) { + if (Object.prototype.toString.call(arg1) === '[object Function]') { return { metadata: new Metadata(), options: {}, callback: arg1 }; - } else if (arg2 instanceof Function) { + } else if (Object.prototype.toString.call(arg2) === '[object Function]') { if (arg1 instanceof Metadata) { return { metadata: arg1, options: {}, callback: arg2 }; } else { @@ -211,7 +211,7 @@ export class Client { !( arg1 instanceof Metadata && arg2 instanceof Object && - arg3 instanceof Function + Object.prototype.toString.call(arg3) === '[object Function]' ) ) { throw new Error('Incorrect arguments passed'); From 7a8cd5a4bde13cde54b41847607fa6c83a4c906d Mon Sep 17 00:00:00 2001 From: zereraz Date: Sat, 24 Apr 2021 14:00:05 +0530 Subject: [PATCH 04/13] grpc-js: Use helper isFunction --- packages/grpc-js/src/client.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 2f995e82..c1db5078 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -55,6 +55,10 @@ const INTERCEPTOR_SYMBOL = Symbol(); const INTERCEPTOR_PROVIDER_SYMBOL = Symbol(); const CALL_INVOCATION_TRANSFORMER_SYMBOL = Symbol(); +function isFunction(arg: Metadata | CallOptions | UnaryCallback): boolean { + return Object.prototype.toString.call(arg) === '[object Function]' +} + export interface UnaryCallback { (err: ServiceError | null, value?: ResponseType): void; } @@ -198,9 +202,9 @@ export class Client { options: CallOptions; callback: UnaryCallback; } { - if (Object.prototype.toString.call(arg1) === '[object Function]') { + if (isFunction(arg1)) { return { metadata: new Metadata(), options: {}, callback: arg1 }; - } else if (Object.prototype.toString.call(arg2) === '[object Function]') { + } else if (isFunction(arg2)) { if (arg1 instanceof Metadata) { return { metadata: arg1, options: {}, callback: arg2 }; } else { @@ -211,7 +215,7 @@ export class Client { !( arg1 instanceof Metadata && arg2 instanceof Object && - Object.prototype.toString.call(arg3) === '[object Function]' + isFunction(arg3) ) ) { throw new Error('Incorrect arguments passed'); @@ -671,3 +675,4 @@ export class Client { return stream; } } + From 923b44bb1c22bf4c4a7605eebb3f70a8df65ef98 Mon Sep 17 00:00:00 2001 From: zereraz Date: Wed, 28 Apr 2021 00:18:23 +0530 Subject: [PATCH 05/13] grpc-js: Add type predicate to fix errors for isFunction --- packages/grpc-js/src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index c1db5078..850e839c 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -55,7 +55,7 @@ const INTERCEPTOR_SYMBOL = Symbol(); const INTERCEPTOR_PROVIDER_SYMBOL = Symbol(); const CALL_INVOCATION_TRANSFORMER_SYMBOL = Symbol(); -function isFunction(arg: Metadata | CallOptions | UnaryCallback): boolean { +function isFunction(arg: Metadata | CallOptions | UnaryCallback | undefined): arg is UnaryCallback{ return Object.prototype.toString.call(arg) === '[object Function]' } From 9253b7f1043770f6a2fa465d996f4a41668d4e0a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 30 Apr 2021 12:53:26 -0700 Subject: [PATCH 06/13] grpc-js: Don't transition out of idle when discarding subchannels --- packages/grpc-js/src/subchannel.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 772bdb22..7a68a1a2 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -598,7 +598,6 @@ export class Subchannel { this.transitionToState( [ ConnectivityState.CONNECTING, - ConnectivityState.IDLE, ConnectivityState.READY, ], ConnectivityState.TRANSIENT_FAILURE From cc0c8deea39ae3e9d744527104100a7ac39dc578 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 6 May 2021 13:09:16 -0700 Subject: [PATCH 07/13] grpc-js: Make GRPC_VERBOSITY accept lower-case values --- packages/grpc-js/src/logging.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 1140e8d8..dea9c93f 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -22,7 +22,7 @@ let _logVerbosity: LogVerbosity = LogVerbosity.ERROR; const verbosityString = process.env.GRPC_NODE_VERBOSITY ?? process.env.GRPC_VERBOSITY ?? ''; -switch (verbosityString) { +switch (verbosityString.toUpperCase()) { case 'DEBUG': _logVerbosity = LogVerbosity.DEBUG; break; From f009cd7b9fdbca41106078e2559669a24794390f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 6 May 2021 10:58:32 -0700 Subject: [PATCH 08/13] grpc-js: Look for ECONNRESET errors by code instead of errno --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 04fa4585..f0e87920 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.0", + "version": "1.3.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 8fcc7065..57693343 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -589,7 +589,7 @@ export class Http2CallStream implements Call { * "Internal server error" message. */ details = `Received RST_STREAM with code ${stream.rstCode} (Internal server error)`; } else { - if (this.internalError.errno === os.constants.errno.ECONNRESET) { + if (this.internalError.code === 'ECONNRESET') { code = Status.UNAVAILABLE; details = this.internalError.message; } else { From bf7d2007917f76bd7af76725043d8ba1f1df981e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 13 May 2021 10:36:06 -0700 Subject: [PATCH 09/13] grpc-js: Change function check to handle async functions --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/client.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f0e87920..6bce0ebd 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.1", + "version": "1.3.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 850e839c..204be901 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -56,7 +56,7 @@ const INTERCEPTOR_PROVIDER_SYMBOL = Symbol(); const CALL_INVOCATION_TRANSFORMER_SYMBOL = Symbol(); function isFunction(arg: Metadata | CallOptions | UnaryCallback | undefined): arg is UnaryCallback{ - return Object.prototype.toString.call(arg) === '[object Function]' + return typeof arg === 'function'; } export interface UnaryCallback { From 118a6df067c68a26c17a4c114747a39ab3621035 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 18 Jun 2021 14:37:03 -0700 Subject: [PATCH 10/13] grpc-js: Make logging behavior more similar to core --- packages/grpc-js/src/constants.ts | 1 + packages/grpc-js/src/logging.ts | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/constants.ts b/packages/grpc-js/src/constants.ts index d30b78f0..94763cfe 100644 --- a/packages/grpc-js/src/constants.ts +++ b/packages/grpc-js/src/constants.ts @@ -39,6 +39,7 @@ export enum LogVerbosity { DEBUG = 0, INFO, ERROR, + NONE, } /** diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index dea9c93f..71683dbf 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -32,6 +32,9 @@ switch (verbosityString.toUpperCase()) { case 'ERROR': _logVerbosity = LogVerbosity.ERROR; break; + case 'NONE': + _logVerbosity = LogVerbosity.NONE; + break; default: // Ignore any other values } @@ -56,15 +59,23 @@ export const log = (severity: LogVerbosity, ...args: any[]): void => { }; const tracersString = process.env.GRPC_NODE_TRACE ?? process.env.GRPC_TRACE ?? ''; -const enabledTracers = tracersString.split(','); -const allEnabled = enabledTracers.includes('all'); +const enabledTracers = new Set(); +const disabledTracers = new Set(); +for (const tracerName of tracersString.split(',')) { + if (tracerName.startsWith('-')) { + disabledTracers.add(tracerName.substring(1)); + } else { + enabledTracers.add(tracerName) + } +} +const allEnabled = enabledTracers.has('all'); export function trace( severity: LogVerbosity, tracer: string, text: string ): void { - if (allEnabled || enabledTracers.includes(tracer)) { + if (!disabledTracers.has(tracer) && (allEnabled || enabledTracers.has(tracer))) { log(severity, new Date().toISOString() + ' | ' + tracer + ' | ' + text); } } From d894809e0eeec1c12d83e272c75f0a96d9e58013 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Jun 2021 14:42:09 -0700 Subject: [PATCH 11/13] grpc-js: Bump version to 1.3.3 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 6bce0ebd..f859a326 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.2", + "version": "1.3.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From fa5066759d239f34c4cf20bf41a16ca9a5f47bf8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 23 Jun 2021 14:01:56 -0700 Subject: [PATCH 12/13] grpc-js: Unref timers for keepalive functionality --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f859a326..8acb8a14 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.3", + "version": "1.3.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 7a68a1a2..8991ee3b 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -280,6 +280,7 @@ export class Subchannel { this.keepaliveTimeoutId = setTimeout(() => { this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); }, this.keepaliveTimeoutMs); + this.keepaliveTimeoutId.unref?.(); this.session!.ping( (err: Error | null, duration: number, payload: Buffer) => { clearTimeout(this.keepaliveTimeoutId); @@ -291,6 +292,7 @@ export class Subchannel { this.keepaliveIntervalId = setInterval(() => { this.sendPing(); }, this.keepaliveTimeMs); + this.keepaliveIntervalId.unref?.() /* Don't send a ping immediately because whatever caused us to start * sending pings should also involve some network activity. */ } From 0ad7cc1ec913d159a22e8c2bf2410322c1b364da Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 28 Jun 2021 14:37:21 -0700 Subject: [PATCH 13/13] grpc-js-xds: case_sensitive flag should not affect regex matcher --- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/src/matcher.ts | 4 ++-- packages/grpc-js-xds/src/resolver-xds.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index f4f8d604..dfd778bd 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.3.0", + "version": "1.3.1", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { diff --git a/packages/grpc-js-xds/src/matcher.ts b/packages/grpc-js-xds/src/matcher.ts index a70cf5d6..14cb7f67 100644 --- a/packages/grpc-js-xds/src/matcher.ts +++ b/packages/grpc-js-xds/src/matcher.ts @@ -197,8 +197,8 @@ export class PathExactValueMatcher { export class PathSafeRegexValueMatcher { private targetRegexImpl: RE2; - constructor(targetRegex: string, caseInsensitive: boolean) { - this.targetRegexImpl = new RE2(`^${targetRegex}$`, caseInsensitive ? 'iu' : 'u'); + constructor(targetRegex: string) { + this.targetRegexImpl = new RE2(`^${targetRegex}$`, 'u'); } apply(value: string) { diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 102a5234..aee7290b 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -169,7 +169,7 @@ function getPredicateForMatcher(routeMatch: RouteMatch__Output): Matcher { pathMatcher = new PathExactValueMatcher(routeMatch.path!, caseInsensitive); break; case 'safe_regex': - pathMatcher = new PathSafeRegexValueMatcher(routeMatch.safe_regex!.regex, caseInsensitive); + pathMatcher = new PathSafeRegexValueMatcher(routeMatch.safe_regex!.regex); break; default: pathMatcher = new RejectValueMatcher();