9

The documentation on Timers for nodejs says that setTimeout will return a timeoutId http://nodejs.org/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?

3
  • 1
    Why don't you just store this timeoutId object in some Array, then send to Redis its index instead? 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... 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? Commented Jan 30, 2013 at 21:09

3 Answers 3

2

I 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

Sign up to request clarification or add additional context in comments.

Comments

1

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.

1 Comment

the doc (nodejs.org/docs/v0.8.1/api/timers.html) says setTimeout returns a timeoutId, but this is definitely an object, but since it looks like a linked list, it can be serialized to JSON because of the cycles.
0

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];
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.