From 7ca0cc006922588190597278288b65007f30ad7d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 17 Aug 2022 16:32:20 -0700 Subject: [PATCH 1/2] grpc-js-xds: Implement ignore_resource_deletion option --- packages/grpc-js-xds/src/xds-client.ts | 4 +++ .../src/xds-stream-state/xds-stream-state.ts | 36 +++++++++++++++---- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index d2b3f1823..0c8126cbe 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -360,6 +360,10 @@ export class XdsClient { } else { this.apiVersion = XdsApiVersion.V2; } + if (bootstrapInfo.xdsServers[0].serverFeatures.indexOf('ignore_resource_deletion') >= 0) { + this.adsState.lds.enableIgnoreResourceDeletion(); + this.adsState.cds.enableIgnoreResourceDeletion(); + } const nodeV2: NodeV2 = { ...bootstrapInfo.node, build_version: `gRPC Node Pure JS ${clientVersion}`, diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index 0b806f843..88d36c77d 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -75,6 +75,7 @@ interface SubscriptionEntry { watchers: Watcher[]; cachedResponse: ResponseType | null; resourceTimer: NodeJS.Timer; + deletionIgnored: boolean; } const RESOURCE_TIMEOUT_MS = 15_000; @@ -86,11 +87,12 @@ export abstract class BaseXdsStreamState implements XdsStreamState private subscriptions: Map> = new Map>(); private latestIsV2 = false; private isAdsStreamRunning = false; + private ignoreResourceDeletion = false; constructor(private updateResourceNames: () => void) {} - protected trace(text: string) { - experimental.trace(logVerbosity.DEBUG, TRACER_NAME, this.getProtocolName() + ' | ' + text); + protected trace(text: string, verbosity = logVerbosity.DEBUG) { + experimental.trace(verbosity, TRACER_NAME, this.getProtocolName() + ' | ' + text); } private startResourceTimer(subscriptionEntry: SubscriptionEntry) { @@ -111,7 +113,8 @@ export abstract class BaseXdsStreamState implements XdsStreamState subscriptionEntry = { watchers: [], cachedResponse: null, - resourceTimer: setTimeout(() => {}, 0) + resourceTimer: setTimeout(() => {}, 0), + deletionIgnored: false }; if (this.isAdsStreamRunning) { this.startResourceTimer(subscriptionEntry); @@ -142,6 +145,9 @@ export abstract class BaseXdsStreamState implements XdsStreamState } if (subscriptionEntry.watchers.length === 0) { clearTimeout(subscriptionEntry.resourceTimer); + if (subscriptionEntry.deletionIgnored) { + this.trace('Unsubscribing from resource with previously ignored deletion: ' + resourceName, logVerbosity.INFO); + } this.subscriptions.delete(resourceName); this.updateResourceNames(); } @@ -187,6 +193,10 @@ export abstract class BaseXdsStreamState implements XdsStreamState } clearTimeout(subscriptionEntry.resourceTimer); subscriptionEntry.cachedResponse = resource; + if (subscriptionEntry.deletionIgnored) { + this.trace('Received resource with previously ignored deletion: ' + resourceName, logVerbosity.INFO); + subscriptionEntry.deletionIgnored = false; + } } } result.missing = this.handleMissingNames(allResourceNames); @@ -218,10 +228,18 @@ export abstract class BaseXdsStreamState implements XdsStreamState const missingNames: string[] = []; for (const [resourceName, subscriptionEntry] of this.subscriptions.entries()) { if (!allResponseNames.has(resourceName) && subscriptionEntry.cachedResponse !== null) { - this.trace('Reporting resource does not exist named ' + resourceName); - missingNames.push(resourceName); - for (const watcher of subscriptionEntry.watchers) { - watcher.onResourceDoesNotExist(); + if (this.ignoreResourceDeletion) { + if (!subscriptionEntry.deletionIgnored) { + this.trace('Ignoring nonexistent resource ' + resourceName, logVerbosity.ERROR); + subscriptionEntry.deletionIgnored = true; + } + } else { + this.trace('Reporting resource does not exist named ' + resourceName); + missingNames.push(resourceName); + for (const watcher of subscriptionEntry.watchers) { + watcher.onResourceDoesNotExist(); + } + subscriptionEntry.cachedResponse = null; } } } @@ -231,6 +249,10 @@ export abstract class BaseXdsStreamState implements XdsStreamState } } + enableIgnoreResourceDeletion() { + this.ignoreResourceDeletion = true; + } + /** * Apply the validation rules for this resource type to this resource * instance. From a3b698e837cfa6cc5be0c989b2d0f2db7694af65 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 17 Aug 2022 17:00:02 -0700 Subject: [PATCH 2/2] Don't use tracer for ignored resource deletion logs --- .../src/xds-stream-state/xds-stream-state.ts | 10 +++++----- packages/grpc-js/src/experimental.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index 88d36c77d..7b3bc0189 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -91,8 +91,8 @@ export abstract class BaseXdsStreamState implements XdsStreamState constructor(private updateResourceNames: () => void) {} - protected trace(text: string, verbosity = logVerbosity.DEBUG) { - experimental.trace(verbosity, TRACER_NAME, this.getProtocolName() + ' | ' + text); + protected trace(text: string) { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, this.getProtocolName() + ' | ' + text); } private startResourceTimer(subscriptionEntry: SubscriptionEntry) { @@ -146,7 +146,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState if (subscriptionEntry.watchers.length === 0) { clearTimeout(subscriptionEntry.resourceTimer); if (subscriptionEntry.deletionIgnored) { - this.trace('Unsubscribing from resource with previously ignored deletion: ' + resourceName, logVerbosity.INFO); + experimental.log(logVerbosity.INFO, 'Unsubscribing from resource with previously ignored deletion: ' + resourceName); } this.subscriptions.delete(resourceName); this.updateResourceNames(); @@ -194,7 +194,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState clearTimeout(subscriptionEntry.resourceTimer); subscriptionEntry.cachedResponse = resource; if (subscriptionEntry.deletionIgnored) { - this.trace('Received resource with previously ignored deletion: ' + resourceName, logVerbosity.INFO); + experimental.log(logVerbosity.INFO, 'Received resource with previously ignored deletion: ' + resourceName); subscriptionEntry.deletionIgnored = false; } } @@ -230,7 +230,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState if (!allResponseNames.has(resourceName) && subscriptionEntry.cachedResponse !== null) { if (this.ignoreResourceDeletion) { if (!subscriptionEntry.deletionIgnored) { - this.trace('Ignoring nonexistent resource ' + resourceName, logVerbosity.ERROR); + experimental.log(logVerbosity.ERROR, 'Ignoring nonexistent resource ' + resourceName); subscriptionEntry.deletionIgnored = true; } } else { diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index fcafbeb01..d58495f46 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -1,4 +1,4 @@ -export { trace } from './logging'; +export { trace, log } from './logging'; export { Resolver, ResolverListener,