I have a custom connect function that creates a promise I want resolved once I make a websocket call and receive an acknowledgement. The remote server may be up, it may be down, but if it's unavailable I want to keep trying until I'm successful.
const socketIOClient = require('socket.io-client');
function createTimeoutCallback(callback)
{
let called = false;
let timerID = setTimeout(() => {
if (called) return;
called = true;
callback(new TimeoutError());
},
60*1000);
return function() {
if (called) return;
called = true;
clearTimeout(timerID);
callback.apply(this, arguments);
}
}
async function myConnect()
{
let mysocket = socketIOClient(url);
return new Promise((resolve, reject) => {
mysocket.emit('clientconnect', args, createTimeoutCallback((resp) => {
if (!(resp instanceof TimeoutError)) {
// SUCCESS
doSomething();
resolve();
}
// We timed out, try again
else {
mysocket.close();
setTimeout(myConnect, 60*1000);
}
}));
});
}
await connect();
// doSomething() gets called but we never get here
In the above code, if the endpoint is available, everything works fine. But I'm never returning from the myConnect() function when (1) I wait on its promise; and (2) the function needs to make several connection attempts (e.g., the server is not initially up); and (3) the endpoint finally comes back online and the connection succeeds. I suspect this has everything to do with me essentially abandoning the original promise on a reconnect attempt, but I don't want to reject it or the operation will prematurely fail.
I did find a workaround, which relies on an embedded function. With this technique there is only one promise which is always accessible and in scope, and the timer-based recursion (i.e., not stack-based) is always wrapped in that single promise that is never abandoned. I put this together before Jaromanda answered, so I can't confirm that his solution would work.
async function myConnect()
{
return new Promise((resolve, reject) => {
function innerConnect()
{
let mysocket = socketIOClient(url);
mysocket.emit('clientconnect', args, createTimeoutCallback((resp) => {
if (!(resp instanceof TimeoutError)) {
// SUCCESS
doSomething();
resolve();
}
// We timed out, try again
else {
mysocket.close();
setTimeout(innerConnect, 60*1000);
}
}));
}
innerConnect();
});
}