Skip to content

Commit 5c9a792

Browse files
authored
Merge pull request #283 from kjin/v1.11.x-backport-275
Backport #275 to v1.11.x
2 parents d5a3e5d + 9112ac1 commit 5c9a792

File tree

3 files changed

+40
-8
lines changed

3 files changed

+40
-8
lines changed

packages/grpc-js-core/src/call.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,13 @@ function setUpReadableStream<ResponseType>(
8787
stream.push(null);
8888
});
8989
call.on('status', (status: StatusObject) => {
90-
stream.emit('status', status);
9190
if (status.code !== Status.OK) {
9291
const statusName = _.invert(Status)[status.code];
9392
const message: string = `${status.code} ${statusName}: ${status.details}`;
9493
const error: ServiceError = Object.assign(new Error(status.details), status);
9594
stream.emit('error', error);
9695
}
96+
stream.emit('status', status);
9797
});
9898
call.pause();
9999
}

packages/grpc-js-core/src/channel.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ export class Http2Channel extends EventEmitter implements Channel {
8585
private readonly target: url.URL;
8686
private readonly defaultAuthority: string;
8787
private connectivityState: ConnectivityState = ConnectivityState.IDLE;
88+
// Helper Promise object only used in the implementation of connect().
89+
private connecting: Promise<void>|null = null;
8890
/* For now, we have up to one subchannel, which will exist as long as we are
8991
* connecting or trying to connect */
9092
private subChannel: http2.ClientHttp2Session|null = null;
@@ -127,6 +129,7 @@ export class Http2Channel extends EventEmitter implements Channel {
127129
this.subChannel.removeListener('connect', this.subChannelConnectCallback);
128130
this.subChannel.removeListener('close', this.subChannelCloseCallback);
129131
this.subChannel = null;
132+
this.emit('shutdown');
130133
clearTimeout(this.backoffTimerId);
131134
}
132135
break;
@@ -279,15 +282,38 @@ export class Http2Channel extends EventEmitter implements Channel {
279282
return stream;
280283
}
281284

285+
/**
286+
* Attempts to connect, returning a Promise that resolves when the connection
287+
* is successful, or rejects if the channel is shut down.
288+
*/
282289
connect(): Promise<void> {
283-
return new Promise((resolve) => {
284-
this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING);
285-
if (this.connectivityState === ConnectivityState.READY) {
286-
setImmediate(resolve);
287-
} else {
288-
this.once('connect', resolve);
290+
if (this.connectivityState === ConnectivityState.READY) {
291+
return Promise.resolve();
292+
} else if (this.connectivityState === ConnectivityState.SHUTDOWN) {
293+
return Promise.reject(new Error('Channel has been shut down'));
294+
} else {
295+
// In effect, this.connecting is only assigned upon the first attempt to
296+
// transition from IDLE to CONNECTING, so this condition could have also
297+
// been (connectivityState === IDLE).
298+
if (!this.connecting) {
299+
this.connecting = new Promise((resolve, reject) => {
300+
this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING);
301+
const onConnect = () => {
302+
this.connecting = null;
303+
this.removeListener('shutdown', onShutdown);
304+
resolve();
305+
};
306+
const onShutdown = () => {
307+
this.connecting = null;
308+
this.removeListener('connect', onConnect);
309+
reject(new Error('Channel has been shut down'));
310+
};
311+
this.once('connect', onConnect);
312+
this.once('shutdown', onShutdown);
313+
});
289314
}
290-
});
315+
return this.connecting;
316+
}
291317
}
292318

293319
getConnectivityState(): ConnectivityState {

packages/grpc-js-core/src/client.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ export class Client {
4242
clearTimeout(timer);
4343
}
4444
cb(null);
45+
}, (err: Error) => {
46+
// Rejection occurs if channel is shut down first.
47+
if (timer) {
48+
clearTimeout(timer);
49+
}
50+
cb(err);
4551
});
4652
if (deadline !== Infinity) {
4753
let timeout: number;

0 commit comments

Comments
 (0)