Skip to content

Commit

Permalink
fix(socket): improve error event retry connection process
Browse files Browse the repository at this point in the history
  • Loading branch information
b-ma committed Sep 5, 2024
1 parent 90fa70f commit d2264f1
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 36 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
"scripts": {
"doc": "npm run types && rm -rf docs && jsdoc -c .jsdoc --verbose && cp -R misc/assets docs/",
"lint": "npx eslint src",
"test": "npx mocha",
"test:all": "npx mocha tests/*/*.spec.js",
"test": "npx mocha tests/*/*.spec.js",
"test:only": "npx mocha",
"types": "rm -rf types && tsc",
"preversion": "node ./misc/scripts/generate-version-file.js $npm_new_version",
"postversion": "node ./misc/scripts/check-changelog.js && git commit -am \"$npm_new_version\" --allow-empty"
Expand Down
53 changes: 19 additions & 34 deletions src/client/ClientSocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,26 +113,17 @@ class ClientSocket {
// Init socket
// ----------------------------------------------------------
return new Promise(resolve => {
let connectionRefusedLogged = false;
let hangingTimeoutDuration = 5;

const trySocket = async () => {
const ws = new WebSocket(url, webSocketOptions);

// If after a given delay, we receive neither an 'open' nor an 'error'
// message (e.g. hardware is not ready), let's just drop and recreate a new socket
// cf. https://github.com/collective-soundworks/soundworks/issues/97
const hangingTimeoutId = setTimeout(() => {
ws.terminate ? ws.terminate() : ws.close();
trySocket();
}, hangingTimeoutDuration * 1000);
// Exponentialy increase hangingTimeoutDuration on each try and clamp at 40sec
// i.e.: 5, 10, 20, 40, 40, 40, ...
hangingTimeoutDuration = Math.min(hangingTimeoutDuration * 2, 40);
// WebSocket "native" events:
// - `close`: Fired when a connection with a websocket is closed.
// - `error`: Fired when a connection with a websocket has been closed
// because of an error, such as whensome data couldn't be sent.
// - `message`: Fired when data is received through a websocket.
// - `open`: Fired when a connection with a websocket is opened.

ws.addEventListener('open', openEvent => {
clearTimeout(hangingTimeoutId);
// parse incoming messages for pubsub
this.#socket = ws;

this.#socket.addEventListener('message', e => {
Expand All @@ -141,16 +132,13 @@ class ClientSocket {
return; // do not propagate ping pong messages
}

// Parse incoming message and dispatch in pubsub system.
const [channel, args] = unpackStringMessage(e.data);
this.#dispatchEvent(channel, ...args);
});

// propagate "native" events
// - `close`: Fired when a connection with a websocket is closed.
// - `error`: Fired when a connection with a websocket has been closed
// because of an error, such as whensome data couldn't be sent.
// - `message`: Fired when data is received through a websocket.
// - `open`: Fired when a connection with a websocket is opened.
// @todo - propagate raw 'message' events in the callback above, no
// need to execute to function instad of one per message...
['close', 'error', 'upgrade', 'message'].forEach(eventName => {
this.#socket.addEventListener(eventName, e => {
this.#dispatchEvent(eventName, e);
Expand All @@ -163,21 +151,18 @@ class ClientSocket {
});

// cf. https://github.com/collective-soundworks/soundworks/issues/17
// cf. https://github.com/collective-soundworks/soundworks/issues/97
ws.addEventListener('error', e => {
clearTimeout(hangingTimeoutId);

if (e.type === 'error') {
ws.terminate ? ws.terminate() : ws.close();
// Try to establish new connection in 1 second
if (e.error && e.error.code === 'ECONNREFUSED') {
if (!connectionRefusedLogged) {
logger.log('[soundworks.Socket] Connection refused, waiting for the server to start');
connectionRefusedLogged = true;
}

setTimeout(trySocket, this.#socketOptions.retryConnectionRefusedTimeout);
}
ws.terminate ? ws.terminate() : ws.close();

if (e.error) {
const msg = `[Socket Error] code: ${e.error.code}, message: ${e.error.message}`;
logger.log(msg);
}

// Try to reconnect in all cases. Note that if the socket has been connected,
// the close event will be propagated and the launcher will restart the process.
setTimeout(trySocket, 1000);
});
};

Expand Down

0 comments on commit d2264f1

Please sign in to comment.