Storing the return value of node.js setTimeout in redis

后端 未结 3 1179
礼貌的吻别
礼貌的吻别 2021-02-13 09:48

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 wan

相关标签:
3条回答
  • 2021-02-13 10:33

    This code is used when the timeouts need not be persistent across server restarts

    var timeouts = {};
    
    app.get('/', function (req, res) {
      var index = timeouts.length;
      timeouts[index] = setTimeout(console.log, 1000000, req.user.name);
    
      redis.set('timeout:' + req.user.name, index, function (err, reply) {
        res.end();
      });
    });
    
    app.get('/clear', function (req, res) {
      redis.get('timeout:' + req.user.name, function (err, index) {
       clearTimeout(timeouts[index]);
       delete timeouts[index];
       redis.delete('timeout:' + req.user.name);
       res.end();
      });
    });
    

    If you need timeouts to be persistent across server restarts, then you might need to store _idleStart and _idleTimeout values for every timer in the redis, and load them up everytime you server restarts

    app.get('/', function (req, res) {
      var timeout = setTimeout(console.log, 1000000, req.user.name);
      var time = timeout._idleStart.getTime() + timeout._idleTimeout;
    
      redis.set('timeout:' + req.user.name, time, function (err, reply) {
        res.end();
      });
    });
    
    app.get('/clear', function (req, res) {
      redis.delete('timeout:' + req.user.name);
      res.end();
    });
    
    // Load timeouts on server start
    // *I know this is not the correct redis command*
    // *It's not accurate, only approx*
    redis.get('timeout:*', function (err, vals) {
      vals.forEach(function (val) {
        var time = val - new Date().getTime();
        setTimeout(console.log, time, username)
      });
    });
    
    0 讨论(0)
  • 2021-02-13 10:36

    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]);
    
    0 讨论(0)
  • 2021-02-13 10:47

    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.

    0 讨论(0)
提交回复
热议问题