I am trying to synchronise a singleton. I would need to make this method like the equivalent of synchronized in java. What happens to me is that because the socket takes a while, if the first two requests are very close together I get two websockets created. (Then from the third one onwards it takes the instance correctly).
import io from 'socket.io-client';
export default class SocketIo {
static socket = null;
static instance = null;
async initialize() {
this.socket = await io(`http://${ip}:10300/`, {
transports: ['websocket'],
});
}
static async getInstance() {
logger.info('socketIo.api.getInstance: BEGIN');
if (!this.instance) {
logger.info('socketIo.api.getInstance: creating new socket instance...');
try {
const o = new SocketIo();
await o.initialize();
this.instance = o;
logger.info('socketIo.api.getInstance: socket instance created SUCCESSFULLY');
} catch (e) {
moaLog('socketIo.api.getInstance: ERROR: ', e);
throw e;
}
} else {
logger.info('socketIo.api.getInstance: a socket instance already exists, reusing that one');
}
logger.info('socketIo.api.getInstance: END');
return this.instance;
}
}
in main.js
var socket1 = SocketIo.getInstance();
var socket2 = SocketIo.getInstance();
// ... after a while
var socket3 = SocketIo.getInstance();
2022-06-16T17:53:40.658Z: socketIo.api.getInstance: BEGIN
2022-06-16T17:53:40.660Z: socketIo.api.getInstance: creating new socket instance...
2022-06-16T17:53:41.140Z: socketIo.api.getInstance: BEGIN
2022-06-16T17:53:41.141Z: socketIo.api.getInstance: creating new socket instance...
2022-06-16T17:53:41.379Z: socketIo.api.getInstance: socket instance created SUCCESSFULLY
2022-06-16T17:53:41.382Z: socketIo.api.getInstance: END
2022-06-16T17:53:41.411Z: socketIo.api.getInstance: socket instance created SUCCESSFULLY
2022-06-16T17:53:41.415Z: socketIo.api.getInstance: END
...
2022-06-16T17:56:13.076Z: socketIo.api.getInstance: BEGIN
2022-06-16T17:56:13.078Z: socketIo.api.getInstance: a socket instance already exists, reusing that one
2022-06-16T17:56:13.079Z: socketIo.api.getInstance: END
And from server view I see two websocket connections.
Any ideas?
I solved using async-lock.
import AsyncLock from 'async-lock';
const lock = new AsyncLock();
export default class SocketIo {
// ...
static async getInstance() {
logger.info('socketIo.api.getInstance: BEGIN');
if (!this.instance) {
logger.info('socketIo.api.getInstance: creating new socket instance...');
try {
await lock.acquire('socketIo', async () => {
if (!this.instance) {
const o = new SocketIo();
await o.initialize();
this.instance = o;
logger.info('socketIo.api.getInstance: socket instance created SUCCESSFULLY');
}
});
} catch (e) {
moaLog('socketIo.api.getInstance: ERROR: ', e);
throw e;
}
} else {
logger.info('socketIo.api.getInstance: a socket instance already exists, reusing that one');
}
logger.info('socketIo.api.getInstance: END');
return this.instance;
}
}