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?
Below is an attempt to synchronize your singleton. The idea is to store the o.intitialize promise and check if it already has been acquired before.
I added an uid, a random value set in initialize to show that only single instance is created.
class SocketIo {
static instance = null;
static _lock = null;
async initialize() {
this.uid = Math.random();
}
static async getInstance() {
console.log('socketIo.api.getInstance: BEGIN');
if (!this.instance) {
console.log('socketIo.api.getInstance: creating new socket instance...');
const o = new SocketIo();
if (!this._lock) {
this._lock = o.initialize();
await this._lock;
this.instance = o;
console.log('socketIo.api.getInstance: socket instance created SUCCESSFULLY');
this._lock = null;
} else {
await this._lock;
}
}
console.log('socketIo.api.getInstance: END');
return this.instance;
}
}
async function Main() {
var socket1 = SocketIo.getInstance();
var socket2 = SocketIo.getInstance();
console.log((await socket1).uid);
console.log((await socket2).uid);
}
Main()
Compare it to your version:
class SocketIo {
static instance = null;
async initialize() {
this.uid = Math.random();
}
static async getInstance() {
console.log('socketIo.api.getInstance: BEGIN');
if (!this.instance) {
console.log('socketIo.api.getInstance: creating new socket instance...');
const o = new SocketIo();
await o.initialize();
this.instance = o;
console.log('socketIo.api.getInstance: socket instance created SUCCESSFULLY');
}
console.log('socketIo.api.getInstance: END');
return this.instance;
}
}
async function Main() {
var socket1 = SocketIo.getInstance();
var socket2 = SocketIo.getInstance();
console.log((await socket1).uid);
console.log((await socket2).uid);
}
Main()
Hope this is what suits you.