Skip to content

Instantly share code, notes, and snippets.

@tiagosiebler
Last active May 19, 2021 00:03
Show Gist options
  • Save tiagosiebler/2aaae16001168b1766f7c99aa5f57402 to your computer and use it in GitHub Desktop.
Save tiagosiebler/2aaae16001168b1766f7c99aa5f57402 to your computer and use it in GitHub Desktop.
Websocket monitoring service class
import { EventEmitter } from 'events';
const debug = require('debug')('wsmonitor');
/*
Give it a websocket to monitor and it'll assert connectivity, handling ping/pong events, and emit actionable state events.
Emits events:
- connected : connection successfully opened
- disconnected : connection dropped or was terminated, reconnect required if desired
- wserror : connection saw error
Debug this by launching with `DEBUG=exchange:wsmonitor node index.js ......`
*/
class WSMonitoringService extends EventEmitter {
aliveCheckSeconds: number;
ws: any;
socketMonitoringTimer: any;
isAlive: boolean;
lastAlive: Date;
constructor(webSocket, aliveCheckSeconds = 10) {
super();
this.ws = webSocket;
this.aliveCheckSeconds = aliveCheckSeconds;
this.isAlive = false;
this.setup(webSocket);
}
setup(ws) {
ws.on('error', e => {
this.isAlive = true;
this.handleError(e);
});
ws.on('close', e => {
this.isAlive = true;
this.handleClosed(e);
});
ws.on('open', () => {
this.isAlive = true;
this.emit('connected', ws);
});
ws.on('pong', () => {
this.receivedAliveResponse();
});
ws.on('ping', () => {
this.receivedPing(ws);
});
this.socketMonitoringTimer = setInterval(() => this.checkSocketState(), this.aliveCheckSeconds * 1000);
}
receivedPing(ws) {
debug('received ping, sending response');
try {
ws.pong();
} catch (e) {
debug(`error in sending ping:pong response: ${e.stack || e.message || e}`);
this.handleError(e);
}
}
receivedAliveResponse() {
debug('received pong');
this.isAlive = true;
this.lastAlive = new Date();
}
sendAliveRequest() {
// if alive, we'll get a pong back and and isAlive will be set back to true
this.ws.ping();
}
checkSocketState() {
const ws = this.ws;
if (!this.isAlive) {
debug('isAlive == false');
return ws.terminate();
}
this.isAlive = false;
// ping will throw an exception if the ws closed earlier (e.g no network), so we'll only ping if the socket's still open
if (ws.readyState === ws.OPEN) {
debug('sending ping');
this.sendAliveRequest();
}
}
handleError(e) {
debug('error: ', e);
this.emit('wserror', e);
}
handleClosed(e) {
clearInterval(this.socketMonitoringTimer);
debug('disconnected: ', e);
this.emit('disconnected', e);
}
}
export default WSMonitoringService;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment