Skip to content

Commit b33b8bc

Browse files
committed
grpc-js: Handle race between bindAsync and (try|force)Shutdown
1 parent 7e53472 commit b33b8bc

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

packages/grpc-js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@grpc/grpc-js",
3-
"version": "1.9.4",
3+
"version": "1.9.5",
44
"description": "gRPC Library for Node - pure JS implementation",
55
"homepage": "https://grpc.io/",
66
"repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js",

packages/grpc-js/src/server.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ export class Server {
161161
>();
162162
private sessions = new Map<http2.ServerHttp2Session, ChannelzSessionInfo>();
163163
private started = false;
164+
private shutdown = false;
164165
private options: ChannelOptions;
165166
private serverAddressString = 'null';
166167

@@ -375,6 +376,10 @@ export class Server {
375376
throw new Error('server is already started');
376377
}
377378

379+
if (this.shutdown) {
380+
throw new Error('bindAsync called after shutdown');
381+
}
382+
378383
if (typeof port !== 'string') {
379384
throw new TypeError('port must be a string');
380385
}
@@ -485,6 +490,11 @@ export class Server {
485490
http2Server.once('error', onError);
486491

487492
http2Server.listen(addr, () => {
493+
if (this.shutdown) {
494+
http2Server.close();
495+
resolve(new Error('bindAsync failed because server is shutdown'));
496+
return;
497+
}
488498
const boundAddress = http2Server.address()!;
489499
let boundSubchannelAddress: SubchannelAddress;
490500
if (typeof boundAddress === 'string') {
@@ -583,6 +593,11 @@ export class Server {
583593
http2Server.once('error', onError);
584594

585595
http2Server.listen(address, () => {
596+
if (this.shutdown) {
597+
http2Server.close();
598+
resolve({port: 0, count: 0});
599+
return;
600+
}
586601
const boundAddress = http2Server.address() as AddressInfo;
587602
const boundSubchannelAddress: SubchannelAddress = {
588603
host: boundAddress.address,
@@ -637,6 +652,12 @@ export class Server {
637652
) => {
638653
// We only want one resolution result. Discard all future results
639654
resolverListener.onSuccessfulResolution = () => {};
655+
if (this.shutdown) {
656+
deferredCallback(
657+
new Error(`bindAsync failed because server is shutdown`),
658+
0
659+
);
660+
}
640661
if (addressList.length === 0) {
641662
deferredCallback(
642663
new Error(`No addresses resolved for port ${port}`),
@@ -707,6 +728,7 @@ export class Server {
707728
}
708729

709730
this.started = false;
731+
this.shutdown = true;
710732

711733
// Always destroy any available sessions. It's possible that one or more
712734
// tryShutdown() calls are in progress. Don't wait on them to finish.
@@ -785,6 +807,7 @@ export class Server {
785807

786808
// Close the server if necessary.
787809
this.started = false;
810+
this.shutdown = true;
788811

789812
for (const { server: http2Server, channelzRef: ref } of this
790813
.http2ServerList) {

0 commit comments

Comments
 (0)