Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hotfix: recover from hanging socket #98

Merged
merged 3 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 14 additions & 21 deletions src/client/Socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class Socket {
}

webSocketOptions = {
// handshakeTimeout: 2000,
// do not reject self-signed certificates
rejectUnauthorized: false,
};
}
Expand All @@ -107,8 +109,6 @@ class Socket {
// Init socket
// ----------------------------------------------------------
return new Promise(resolve => {
let connectionRefusedLogged = false;

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

Expand All @@ -118,7 +118,6 @@ class Socket {

this.#socket.addEventListener('message', e => {
if (e.data === PING_MESSAGE) {
// heartbeat();
this.#socket.send(PONG_MESSAGE);
// do not propagate ping / pong messages
return;
Expand Down Expand Up @@ -161,26 +160,20 @@ class Socket {

// cf. https://github.com/collective-soundworks/soundworks/issues/17
ws.addEventListener('error', e => {
if (e.type === 'error') {
if (ws.terminate) {
ws.terminate();
} else {
ws.close();
}
if (ws.terminate) {
ws.terminate();
} else {
ws.close();
}

// for node clients, retry connection
if (e.error && e.error.code === 'ECONNREFUSED') {
// we want to log the warning just once
if (!connectionRefusedLogged) {
logger.log('[soundworks.Socket] Connection refused, waiting for the server to start');
// console.log(e.error);
connectionRefusedLogged = true;
}

// retry in 1 second
setTimeout(trySocket, 1000);
}
if (e.error) {
const msg = `[Socket Error] code: ${e.error.code}, message: ${e.error.message}`;
logger.log(msg);
}

// Try 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
2 changes: 1 addition & 1 deletion tests/essentials/Client.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ describe('# client::Client', () => {
await server.stop();
});

it.only(`[node only] should connect to localhost if serverAddress is empty`, async () => {
it(`[node only] should connect to localhost if serverAddress is empty`, async () => {
const emptyConfig = merge({}, config);
emptyConfig.env.serverAddress = '';

Expand Down
45 changes: 34 additions & 11 deletions tests/essentials/Socket.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ import { kSocketTerminate } from '../../src/client/Socket.js';
import config from '../utils/config.js';

describe('# client::Socket', () => {
let server;
describe(`## "close" event`, () => {
let server;

beforeEach(async () => {
server = new Server(config);
await server.start();
});
beforeEach(async () => {
server = new Server(config);
await server.start();
});

afterEach(async () => {
if (server.status !== 'stopped') {
await server.stop();
}
});
afterEach(async () => {
if (server.status !== 'stopped') {
await server.stop();
}
});

describe(`## "close" event`, () => {
it('should be triggered when calling socket[kSocketTerminate]()', async () => {
const client = new Client({ role: 'test', ...config });
await client.start();
Expand Down Expand Up @@ -65,6 +65,29 @@ describe('# client::Socket', () => {
assert.equal(closeCalled, 1);
});
});

describe('connect retry', () => {
it(`should connect when server is started later than client`, async function() {
this.timeout(4 * 1000);

let connected = false;
const client = new Client({ role: 'test', ...config });
client.start();
client.socket.addListener('open', () => {
connected = true;
});

await delay(2 * 1000);

const server = new Server(config);
await server.start();
// socket connection retry timeout is 1 second
await delay(1 * 1000);
await server.stop();

assert.isTrue(connected);
});
});
});


Loading