Skip to content

Commit

Permalink
Merge pull request #2590 from murgatroid99/grpc-js_server_shutdown_race
Browse files Browse the repository at this point in the history
grpc-js: Handle race between bindAsync and (try|force)Shutdown
  • Loading branch information
murgatroid99 committed Oct 2, 2023
2 parents 1b1903c + b33b8bc commit 065ac2f
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/grpc-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@grpc/grpc-js",
"version": "1.9.4",
"version": "1.9.5",
"description": "gRPC Library for Node - pure JS implementation",
"homepage": "https://grpc.io/",
"repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js",
Expand Down
23 changes: 23 additions & 0 deletions packages/grpc-js/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ export class Server {
>();
private sessions = new Map<http2.ServerHttp2Session, ChannelzSessionInfo>();
private started = false;
private shutdown = false;
private options: ChannelOptions;
private serverAddressString = 'null';

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

if (this.shutdown) {
throw new Error('bindAsync called after shutdown');
}

if (typeof port !== 'string') {
throw new TypeError('port must be a string');
}
Expand Down Expand Up @@ -485,6 +490,11 @@ export class Server {
http2Server.once('error', onError);

http2Server.listen(addr, () => {
if (this.shutdown) {
http2Server.close();
resolve(new Error('bindAsync failed because server is shutdown'));
return;
}
const boundAddress = http2Server.address()!;
let boundSubchannelAddress: SubchannelAddress;
if (typeof boundAddress === 'string') {
Expand Down Expand Up @@ -583,6 +593,11 @@ export class Server {
http2Server.once('error', onError);

http2Server.listen(address, () => {
if (this.shutdown) {
http2Server.close();
resolve({port: 0, count: 0});
return;
}
const boundAddress = http2Server.address() as AddressInfo;
const boundSubchannelAddress: SubchannelAddress = {
host: boundAddress.address,
Expand Down Expand Up @@ -637,6 +652,12 @@ export class Server {
) => {
// We only want one resolution result. Discard all future results
resolverListener.onSuccessfulResolution = () => {};
if (this.shutdown) {
deferredCallback(
new Error(`bindAsync failed because server is shutdown`),
0
);
}
if (addressList.length === 0) {
deferredCallback(
new Error(`No addresses resolved for port ${port}`),
Expand Down Expand Up @@ -707,6 +728,7 @@ export class Server {
}

this.started = false;
this.shutdown = true;

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

// Close the server if necessary.
this.started = false;
this.shutdown = true;

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

0 comments on commit 065ac2f

Please sign in to comment.