mirror of https://github.com/grpc/grpc-node.git
Merge pull request #275 from kjin/grpc-js-connect
grpc-js-core: only listen for channel connect event once
This commit is contained in:
commit
8176c70a94
|
@ -87,13 +87,13 @@ function setUpReadableStream<ResponseType>(
|
||||||
stream.push(null);
|
stream.push(null);
|
||||||
});
|
});
|
||||||
call.on('status', (status: StatusObject) => {
|
call.on('status', (status: StatusObject) => {
|
||||||
stream.emit('status', status);
|
|
||||||
if (status.code !== Status.OK) {
|
if (status.code !== Status.OK) {
|
||||||
const statusName = _.invert(Status)[status.code];
|
const statusName = _.invert(Status)[status.code];
|
||||||
const message: string = `${status.code} ${statusName}: ${status.details}`;
|
const message: string = `${status.code} ${statusName}: ${status.details}`;
|
||||||
const error: ServiceError = Object.assign(new Error(status.details), status);
|
const error: ServiceError = Object.assign(new Error(status.details), status);
|
||||||
stream.emit('error', error);
|
stream.emit('error', error);
|
||||||
}
|
}
|
||||||
|
stream.emit('status', status);
|
||||||
});
|
});
|
||||||
call.pause();
|
call.pause();
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,8 @@ export class Http2Channel extends EventEmitter implements Channel {
|
||||||
private readonly target: url.URL;
|
private readonly target: url.URL;
|
||||||
private readonly defaultAuthority: string;
|
private readonly defaultAuthority: string;
|
||||||
private connectivityState: ConnectivityState = ConnectivityState.IDLE;
|
private connectivityState: ConnectivityState = ConnectivityState.IDLE;
|
||||||
|
// Helper Promise object only used in the implementation of connect().
|
||||||
|
private connecting: Promise<void>|null = null;
|
||||||
/* For now, we have up to one subchannel, which will exist as long as we are
|
/* For now, we have up to one subchannel, which will exist as long as we are
|
||||||
* connecting or trying to connect */
|
* connecting or trying to connect */
|
||||||
private subChannel: http2.ClientHttp2Session|null = null;
|
private subChannel: http2.ClientHttp2Session|null = null;
|
||||||
|
@ -127,6 +129,7 @@ export class Http2Channel extends EventEmitter implements Channel {
|
||||||
this.subChannel.removeListener('connect', this.subChannelConnectCallback);
|
this.subChannel.removeListener('connect', this.subChannelConnectCallback);
|
||||||
this.subChannel.removeListener('close', this.subChannelCloseCallback);
|
this.subChannel.removeListener('close', this.subChannelCloseCallback);
|
||||||
this.subChannel = null;
|
this.subChannel = null;
|
||||||
|
this.emit('shutdown');
|
||||||
clearTimeout(this.backoffTimerId);
|
clearTimeout(this.backoffTimerId);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -279,15 +282,38 @@ export class Http2Channel extends EventEmitter implements Channel {
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to connect, returning a Promise that resolves when the connection
|
||||||
|
* is successful, or rejects if the channel is shut down.
|
||||||
|
*/
|
||||||
connect(): Promise<void> {
|
connect(): Promise<void> {
|
||||||
return new Promise((resolve) => {
|
if (this.connectivityState === ConnectivityState.READY) {
|
||||||
this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING);
|
return Promise.resolve();
|
||||||
if (this.connectivityState === ConnectivityState.READY) {
|
} else if (this.connectivityState === ConnectivityState.SHUTDOWN) {
|
||||||
setImmediate(resolve);
|
return Promise.reject(new Error('Channel has been shut down'));
|
||||||
} else {
|
} else {
|
||||||
this.once('connect', resolve);
|
// In effect, this.connecting is only assigned upon the first attempt to
|
||||||
|
// transition from IDLE to CONNECTING, so this condition could have also
|
||||||
|
// been (connectivityState === IDLE).
|
||||||
|
if (!this.connecting) {
|
||||||
|
this.connecting = new Promise((resolve, reject) => {
|
||||||
|
this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING);
|
||||||
|
const onConnect = () => {
|
||||||
|
this.connecting = null;
|
||||||
|
this.removeListener('shutdown', onShutdown);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
const onShutdown = () => {
|
||||||
|
this.connecting = null;
|
||||||
|
this.removeListener('connect', onConnect);
|
||||||
|
reject(new Error('Channel has been shut down'));
|
||||||
|
};
|
||||||
|
this.once('connect', onConnect);
|
||||||
|
this.once('shutdown', onShutdown);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
return this.connecting;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getConnectivityState(): ConnectivityState {
|
getConnectivityState(): ConnectivityState {
|
||||||
|
|
|
@ -42,6 +42,12 @@ export class Client {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
}
|
}
|
||||||
cb(null);
|
cb(null);
|
||||||
|
}, (err: Error) => {
|
||||||
|
// Rejection occurs if channel is shut down first.
|
||||||
|
if (timer) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
}
|
||||||
|
cb(err);
|
||||||
});
|
});
|
||||||
if (deadline !== Infinity) {
|
if (deadline !== Infinity) {
|
||||||
let timeout: number;
|
let timeout: number;
|
||||||
|
|
Loading…
Reference in New Issue