Skip to content

Commit

Permalink
Bug/msg session reconnect (#2193)
Browse files Browse the repository at this point in the history
* Messaging Session reconnects on failures to fetch messaging session endpoint

Co-authored-by: David Witherspoon <[email protected]>
Co-authored-by: Venkatesh Devale <[email protected]>
  • Loading branch information
3 people committed May 3, 2022
1 parent 53d3d17 commit 9e36201
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 21 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `MessagingSession` reconnects with refreshed endpoint and credentials if needed. EndpointUrl on `MessagingSessionConfiguration` is deprecated as it is resolved by calling `getMessagingSessionEndpoint` internally.

### Removed

### Changed

### Fixed

- `MessagingSession` reconnects with refreshed endpoint and credentials if needed. EndpointUrl on `MessagingSessionConfiguration` is deprecated as it is resolved by calling `getMessagingSessionEndpoint` internally.

## [2.30.0] - 2022-03-08

Expand Down
53 changes: 34 additions & 19 deletions src/messagingsession/DefaultMessagingSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,6 @@ export default class DefaultMessagingSession implements MessagingSession {
private async startConnecting(reconnecting: boolean): Promise<void> {
this.isConnecting = true;
try {
// reconnect needs to re-resolve endpoint url, which will also refresh credentials on client if they are expired.
let endpointUrl = !reconnecting ? this.configuration.endpointUrl : undefined;
if (endpointUrl === undefined) {
const endpoint = await this.configuration.chimeClient
.getMessagingSessionEndpoint()
.promise();
endpointUrl = endpoint.Endpoint.Url;
}

const signedUrl = this.prepareWebSocketUrl(endpointUrl);
this.logger.info(`opening connection to ${signedUrl}`);
if (!reconnecting) {
this.reconnectController.reset();
}
Expand All @@ -126,6 +115,30 @@ export default class DefaultMessagingSession implements MessagingSession {
} else {
this.reconnectController.startedConnectionAttempt(true);
}

// reconnect needs to re-resolve endpoint url, which will also refresh credentials on client if they are expired.
let endpointUrl = !reconnecting ? this.configuration.endpointUrl : undefined;
if (endpointUrl === undefined) {
try {
const endpoint = await this.configuration.chimeClient
.getMessagingSessionEndpoint()
.promise();
endpointUrl = endpoint.Endpoint.Url;
} catch (e) {
const closeEvent = new CloseEvent('close', {
wasClean: false,
code: 4999,
reason: 'Failed to getMessagingSessionEndpoint',
bubbles: false,
});
this.closeEventHandler(closeEvent);
return;
}
}

const signedUrl = this.prepareWebSocketUrl(endpointUrl);
this.logger.info(`opening connection to ${signedUrl}`);

this.webSocket.create(signedUrl, [], true);
this.forEachObserver(observer => {
if (observer.messagingSessionDidStartConnecting) {
Expand Down Expand Up @@ -191,16 +204,18 @@ export default class DefaultMessagingSession implements MessagingSession {
}
}

private retryConnection(): boolean {
return this.reconnectController.retryWithBackoff(async () => {
await this.startConnecting(true);
}, null);
}

private closeEventHandler(event: CloseEvent): void {
this.logger.info(`WebSocket close: ${event.code} ${event.reason}`);
this.webSocket.destroy();
if (
!this.isClosing &&
this.canReconnect(event.code) &&
this.reconnectController.retryWithBackoff(async () => {
await this.startConnecting(true);
}, null)
) {
if (event.code !== 4999) {
this.webSocket.destroy();
}
if (!this.isClosing && this.canReconnect(event.code) && this.retryConnection()) {
return;
}
this.isClosing = false;
Expand Down
41 changes: 41 additions & 0 deletions test/messagingsession/DefaultMessagingSession.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,47 @@ describe('DefaultMessagingSession', () => {
messagingSession.start();
});

it('can reconnect with failures on getMessagingSession', done => {
let didStartCount = 0;
let didStartConnecting = 0;
const savedClientBehavior = chimeClient.getMessagingSessionEndpoint;
messagingSession.addObserver({
messagingSessionDidStartConnecting(reconnecting: boolean): void {
didStartConnecting++;
if (!reconnecting) {
webSocket.addEventListener('open', () => {
webSocket.close(1006);
chimeClient.getMessagingSessionEndpoint = function () {
throw 'some error';
};
setTimeout(function () {
chimeClient.getMessagingSessionEndpoint = savedClientBehavior;
}, 100);
});
} else {
webSocket.addEventListener('open', () => {
webSocket.send(SESSION_SUBSCRIBED_MSG);
});
webSocket.addEventListener('message', (_event: MessageEvent) => {
new TimeoutScheduler(10).start(() => {
messagingSession.stop();
});
});
}
},
messagingSessionDidStart(): void {
didStartCount++;
},
messagingSessionDidStop(_event: CloseEvent): void {
expect(didStartConnecting).to.be.eq(2);
expect(didStartCount).to.be.eq(1);
expect(getMessSessionCnt).to.be.eq(2);
done();
},
});
messagingSession.start();
});

it('will not reconnect', done => {
let didStartConnecting = 0;
messagingSession.addObserver({
Expand Down

0 comments on commit 9e36201

Please sign in to comment.