From 141dfeb790968359a060b4e812f35ae078c32b96 Mon Sep 17 00:00:00 2001 From: Simon Woolf Date: Fri, 21 Aug 2020 18:10:58 +0100 Subject: [PATCH] Channel#watchConnectivityState: handle infinite deadlines correctly Per https://grpc.github.io/grpc/node/grpc.html#~Deadline: "If it is a finite number, it is treated as a number of milliseconds since the Unix Epoch. If it is Infinity, the deadline will never be reached. If it is -Infinity, the deadline has already passed." --- packages/grpc-js/src/channel.ts | 40 +++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 8c3691928..3195ebc2f 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -120,7 +120,7 @@ export interface Channel { interface ConnectivityStateWatcher { currentState: ConnectivityState; - timer: NodeJS.Timeout; + timer: NodeJS.Timeout | null; callback: (error?: Error) => void; } @@ -417,7 +417,9 @@ export class ChannelImplementation implements Channel { const watchersCopy = this.connectivityStateWatchers.slice(); for (const watcherObject of watchersCopy) { if (newState !== watcherObject.currentState) { - clearTimeout(watcherObject.timer); + if(watcherObject.timer) { + clearTimeout(watcherObject.timer); + } this.removeConnectivityStateWatcher(watcherObject); watcherObject.callback(); } @@ -452,25 +454,29 @@ export class ChannelImplementation implements Channel { deadline: Date | number, callback: (error?: Error) => void ): void { - const deadlineDate: Date = - deadline instanceof Date ? deadline : new Date(deadline); - const now = new Date(); - if (deadlineDate <= now) { - process.nextTick( - callback, - new Error('Deadline passed without connectivity state change') - ); - return; - } - const watcherObject = { - currentState, - callback, - timer: setTimeout(() => { + let timer = null; + if(deadline !== Infinity) { + const deadlineDate: Date = + deadline instanceof Date ? deadline : new Date(deadline); + const now = new Date(); + if (deadline === -Infinity || deadlineDate <= now) { + process.nextTick( + callback, + new Error('Deadline passed without connectivity state change') + ); + return; + } + timer = setTimeout(() => { this.removeConnectivityStateWatcher(watcherObject); callback( new Error('Deadline passed without connectivity state change') ); - }, deadlineDate.getTime() - now.getTime()), + }, deadlineDate.getTime() - now.getTime()) + } + const watcherObject = { + currentState, + callback, + timer }; this.connectivityStateWatchers.push(watcherObject); }