I'm using setTimeout
in Node.js and it seems to behave differently from client-side setTimeout
in that it returns an object instead of a number. I want to store this in redis, but since redis only stores strings, I need to convert the object to a string. However, using JSON.stringify
throws a circular reference error. How can I store this object in redis if I want to be able to fetch it from redis and call clearTimeout
on it?
In the newer versions of node, you can use the Id of the Timeout
object instead of the object itself to end the loop.
redisClient.set('time', JSON.stringify(10))
let timeoutObject = setInterval(async function(){
let time = await JSON.parse(redisClient.get('time'))
if(time === 0){
let intervalId = await JSON.parse(redisClient.get('intervalId'))
clearInterval(intervalId)
}
time -= 1
redisClient.set('time', JSON.stringify(time))
}, 1000)
let intervalId = timeoutObject[Symbol.toPrimitive]()
redisClient.set('intervalId', JSON.stringify(intervalId))
This is just an example of a timer built with setInterval
and redis
combined. As you can see, you can grab the Id of the Timeout Object and store that to end setInterval's execution instead of trying to store the whole object.
Here is the link to the node docs: https://nodejs.org/api/timers.html#timers_timeout_symbol_toprimitive
You cannot store the object in Redis. The setTimeout
method returns a Handler (object reference).
One idea would be to create your own associative array in memory, and store the index in Redis. For example:
var nextTimerIndex = 0;
var timerMap = {};
var timer = setTimeout(function(timerIndex) {
console.log('Ding!');
// Free timer reference!
delete timerMap[timerIndex];
}, 5 * 1000, nextTimerIndex);
// Store index in Redis...
// Then, store the timer object for later reference
timerMap[nextTimerIndex++] = timer;
// ...
// To clear the timeout
clearTimeout(timerMap[myTimerIndex]);
I was attempting to do the same thing as the OP. My solution was to set the timeout with a conditional check on a new key inside the timeout in my disconnect handler:
redis.hset("userDisconnecting:" + userId, "disconnect", 1);
setTimeout(function() {
redis.hget("userDisconnecting:" + userId, "disconnect",
function(err, result) {
if (result.toString() === "1") {
//do stuff, like notify other clients of the disconnect.
}
});
}, 10000);
Then, when the client connects again, I set that key to 0
, so the stuff that needs to fire on true disconnect doesn't happen:
redis.hset("userDisconnecting:" + userId, "disconnect", 0);
The timeouts themselves aren't persistent across server restarts, but you could solve that by kicking off a sweeper method on startup. Connected clients would come back "online" pretty quickly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With