From ddec63af2055038ebbe235e73b2371cdd2cfaac0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Aug 2020 11:22:18 -0700 Subject: [PATCH] grpc-js: Clean up call even if status throws an error --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 11 ++++++++++- packages/grpc-js/src/server-call.ts | 6 ++++++ packages/grpc-js/src/server.ts | 12 +++++++++++- packages/grpc-js/src/subchannel.ts | 2 +- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4c4e59f0..70ebe057 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.3", + "version": "1.1.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/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 825342a5..45bc665f 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -227,7 +227,15 @@ export class Http2CallStream implements Call { const filteredStatus = this.filterStack.receiveTrailers( this.finalStatus! ); - this.listener?.onReceiveStatus(filteredStatus); + /* We delay the actual action of bubbling up the status to insulate the + * cleanup code in this class from any errors that may be thrown in the + * upper layers as a result of bubbling up the status. In particular, + * if the status is not OK, the "error" event may be emitted + * synchronously at the top level, which will result in a thrown error if + * the user does not handle that event. */ + process.nextTick(() => { + this.listener?.onReceiveStatus(filteredStatus); + }); if (this.subchannel) { this.subchannel.callUnref(); this.subchannel.removeDisconnectListener(this.disconnectListener); @@ -602,6 +610,7 @@ export class Http2CallStream implements Call { } else { code = http2.constants.NGHTTP2_CANCEL; } + this.trace('close http2 stream with code ' + code); this.http2Stream.close(code); } } diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d88517..fb76ca03 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -373,6 +373,12 @@ export class Http2ServerCallStream< }); this.stream.once('close', () => { + trace( + 'Request to method ' + + this.handler?.path + + ' stream closed with rstCode ' + + this.stream.rstCode + ); this.cancelled = true; this.emit('cancelled', 'cancelled'); }); diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index ebd4504d..3580d89a 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -543,11 +543,21 @@ export class Server { try { const path = headers[http2.constants.HTTP2_HEADER_PATH] as string; + const serverAddress = http2Server.address(); + let serverAddressString = 'null'; + if (serverAddress) { + if (typeof serverAddress === 'string') { + serverAddressString = serverAddress; + } else { + serverAddressString = + serverAddress.address + ':' + serverAddress.port; + } + } trace( 'Received call to method ' + path + ' at address ' + - http2Server.address()?.toString() + serverAddressString ); const handler = this.handlers.get(path); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index be72680e..736562a6 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -415,7 +415,7 @@ export class Subchannel { ); } trace( - this.subchannelAddress + + this.subchannelAddressString + ' connection closed by GOAWAY with code ' + errorCode );