grpc-js: Improve event sequencing when handling connection drops

This commit is contained in:
Michael Lumish 2024-12-04 10:54:50 -05:00
parent a524d15488
commit 5e3b0fb8e0
3 changed files with 26 additions and 15 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@grpc/grpc-js", "name": "@grpc/grpc-js",
"version": "1.12.3", "version": "1.12.4",
"description": "gRPC Library for Node - pure JS implementation", "description": "gRPC Library for Node - pure JS implementation",
"homepage": "https://grpc.io/", "homepage": "https://grpc.io/",
"repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js",

View File

@ -140,6 +140,8 @@ export class Http2SubchannelCall implements SubchannelCall {
private serverEndedCall = false; private serverEndedCall = false;
private connectionDropped = false;
constructor( constructor(
private readonly http2Stream: http2.ClientHttp2Stream, private readonly http2Stream: http2.ClientHttp2Stream,
private readonly callEventTracker: CallEventTracker, private readonly callEventTracker: CallEventTracker,
@ -240,8 +242,16 @@ export class Http2SubchannelCall implements SubchannelCall {
details = 'Stream refused by server'; details = 'Stream refused by server';
break; break;
case http2.constants.NGHTTP2_CANCEL: case http2.constants.NGHTTP2_CANCEL:
code = Status.CANCELLED; /* Bug reports indicate that Node synthesizes a NGHTTP2_CANCEL
details = 'Call cancelled'; * code from connection drops. We want to prioritize reporting
* an unavailable status when that happens. */
if (this.connectionDropped) {
code = Status.UNAVAILABLE;
details = 'Connection dropped';
} else {
code = Status.CANCELLED;
details = 'Call cancelled';
}
break; break;
case http2.constants.NGHTTP2_ENHANCE_YOUR_CALM: case http2.constants.NGHTTP2_ENHANCE_YOUR_CALM:
code = Status.RESOURCE_EXHAUSTED; code = Status.RESOURCE_EXHAUSTED;
@ -321,10 +331,15 @@ export class Http2SubchannelCall implements SubchannelCall {
} }
public onDisconnect() { public onDisconnect() {
this.endCall({ this.connectionDropped = true;
code: Status.UNAVAILABLE, /* Give the call an event loop cycle to finish naturally before reporting
details: 'Connection dropped', * the disconnection as an error. */
metadata: new Metadata(), setImmediate(() => {
this.endCall({
code: Status.UNAVAILABLE,
details: 'Connection dropped',
metadata: new Metadata(),
});
}); });
} }

View File

@ -387,17 +387,13 @@ class Http2Transport implements Transport {
* Handle connection drops, but not GOAWAYs. * Handle connection drops, but not GOAWAYs.
*/ */
private handleDisconnect() { private handleDisconnect() {
if (this.disconnectHandled) {
return;
}
this.clearKeepaliveTimeout(); this.clearKeepaliveTimeout();
this.reportDisconnectToOwner(false); this.reportDisconnectToOwner(false);
/* Give calls an event loop cycle to finish naturally before reporting the for (const call of this.activeCalls) {
* disconnnection to them. */ call.onDisconnect();
}
// Wait an event loop cycle before destroying the connection
setImmediate(() => { setImmediate(() => {
for (const call of this.activeCalls) {
call.onDisconnect();
}
this.session.destroy(); this.session.destroy();
}); });
} }