The documentation on Timers for nodejs says that setTimeout will return a timeoutId .html#timers_cleartimeout_timeoutid
When I use javascript in a web broswer, then I get an integer as a return value.
var b = setTimeout(function(){console.log("Taco Bell")})
// b = 20088
When I use node and do the same thing, the return is
var b = setTimeout(function(){console.log("Taco Bell")})
// { _idleTimeout: 60000,
// _idlePrev:
// { _idleNext: [Circular],
// _idlePrev: [Circular],
// ontimeout: [Function] },
// _idleNext:
// { _idleNext: [Circular],
// _idlePrev: [Circular],
// ontimeout: [Function] },
// _onTimeout: [Function],
// _idleStart: Wed Jan 30 2013 08:23:39 GMT-0800 (PST) }
What I would like to do is store the setTimeout integer into redis and then clear it later. So I try to do something like this
var redis = require('redis');
var redisClient = redis.createClient();
var delay = setTimeout(function(){console.log("hey")}, 20000);
var envelope = { 'body' : 'body text', 'from' : '[email protected]', 'to' : '[email protected]', 'subject' : 'test subject', 'delay' : delay };
redisClient.hset("email", JSON.stringify(envelope), redis.print);
But then I get an error from JSON.stringify about not being able to handle Circular Objects. Is there a way to either have setTimeout return the ID or store enough of the object into redis to be able to clear later?
The documentation on Timers for nodejs says that setTimeout will return a timeoutId http://nodejs/api/timers.html#timers_cleartimeout_timeoutid
When I use javascript in a web broswer, then I get an integer as a return value.
var b = setTimeout(function(){console.log("Taco Bell")})
// b = 20088
When I use node and do the same thing, the return is
var b = setTimeout(function(){console.log("Taco Bell")})
// { _idleTimeout: 60000,
// _idlePrev:
// { _idleNext: [Circular],
// _idlePrev: [Circular],
// ontimeout: [Function] },
// _idleNext:
// { _idleNext: [Circular],
// _idlePrev: [Circular],
// ontimeout: [Function] },
// _onTimeout: [Function],
// _idleStart: Wed Jan 30 2013 08:23:39 GMT-0800 (PST) }
What I would like to do is store the setTimeout integer into redis and then clear it later. So I try to do something like this
var redis = require('redis');
var redisClient = redis.createClient();
var delay = setTimeout(function(){console.log("hey")}, 20000);
var envelope = { 'body' : 'body text', 'from' : '[email protected]', 'to' : '[email protected]', 'subject' : 'test subject', 'delay' : delay };
redisClient.hset("email", JSON.stringify(envelope), redis.print);
But then I get an error from JSON.stringify about not being able to handle Circular Objects. Is there a way to either have setTimeout return the ID or store enough of the object into redis to be able to clear later?
Share Improve this question asked Jan 30, 2013 at 16:57 earlonrailsearlonrails 5,1823 gold badges33 silver badges47 bronze badges 3- 1 Why don't you just store this timeoutId object in some Array, then send to Redis its index instead? – raina77ow Commented Jan 30, 2013 at 17:05
-
Storing a timeout id in a database looks really weird to me... just out of pure curiosity, why do you think you need to do such a strange thing? To me looks not really that different from storing e.g. the memory address of the first element of a C++
std::vector
in a database... – 6502 Commented Jan 30, 2013 at 20:31 - Yeah it might be strange. I have been thinking that I might be making a poor decision, but I would like to start a setTimeout on an http request and then be able to clear the timeout on another http request. I think the Array and Object storage answers are good and would work, but now I feel like I don't really need redis. How would I get the memory location and then if I have it can I stop the timeout with the memory location? – earlonrails Commented Jan 30, 2013 at 21:09
3 Answers
Reset to default 2I really wasn't believing that in nodejs(which I'm so in love)you would be forced to make such functions.
Fortunately there is an undocumented method on setTimeout's return(setInterval also has it!) called close
var timer = setInterval(doSomething, 1000);
setTimeout(function() {
// delete my interval
timer.close()
}, 5000);
Hope it be useful
I would wrap the call to setTimeout into a function that stores the result of setTimeout in an object, so you can retrieve the timeout by their id.
something like this:
var timeouts = {};
var counter = 0;
function setTimeoutReturnsId(callback, delay) {
var current = counter++;
timeouts[current] = setTimeout(function() {
timeouts[current] = null;
callback();
}, delay);
return current;
}
function getTimeoutFromId(id) {
return timeouts[id];
}
of course, when your node server restart, you'd need to clear redis, though.
Been banging my head on this, so here's a modern hack to do it:
In recent versions of node, node timers uses Symbols for this; a timer object has three symbol keys. I needed to add my timers' unique ids to my dev debugging logs, but looking that field up in the handle's map when I don't have the timer system's private Symbol for that field was an obstacle.
(Implementing an entire facade like in the accepted answer is the only way I'd do this if I needed easily printable ids in production; but building that facade just to debug some tricky timer interactions and tear it out again is too much mutation of the very code I'm trying to debug.)
The only kludge I've found is to use util.inspect to stringify the unstringable, and since I'm only keeping the kludge long enough to debug my current module, I'm not worried about another Symbol with the same descriptive string sneaking in from releases or adding other libraries:
function getId(timer) {
var ids = Object.getOwnPropertySymbols(timer); // this currently returns three symbols
var key;
ids.forEach(id => {
if (util.inspect(id) === 'Symbol(triggerId)') key = id;
});
if (!key) throw new Error('Symbol(triggerId) not found in timer');
return timer[key];
}