2012-07-02 4 views
11

Я использую setTimeout в Node.js, и он, похоже, ведет себя иначе, чем клиентская сторона setTimeout тем, что возвращает объект вместо числа. Я хочу сохранить это в redis, но поскольку redis хранит только строки, мне нужно преобразовать объект в строку. Однако использование JSON.stringify вызывает круговую опорную ошибку. Как сохранить этот объект в redis, если я хочу получить его из redis и вызвать на нем clearTimeout?Сохранение возвращаемого значения node.js setTimeout в redis

+0

Я не думаю, что 'setTimeout' вызов не имеет ничего общего с круговой опорной ошибкой. http://stackoverflow.com/questions/1493453/example-of-a-circular-reference-in-javascript – Trevor

+0

@Trevor 'setTimeout' создает этот объект:' {_idleTimeout: 1000000000, _idlePrev: {_idleNext: [Circular ], _idlePrev: [Круговая], ontimeout: [Функция]}, _idleNext: {_idleNext: [Круговая], _idlePrev: [Круговая], ontimeout: [Function]}, _onTimeout: [Function], _idleStart: Пн, 02 июл 2012 20:28:18 GMT} ' – user730569

+1

' _idleNext' и '_idlePrev' ключи кажутся круглыми ссылками ... – user730569

ответ

1

Невозможно сохранить объект в Редисе. Метод setTimeout возвращает обработчик (ссылка на объект).

Одной из идей было бы создание своего собственного ассоциативного массива в памяти и сохранение индекса в Redis. Например:

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

Хорошо, но мне нужно иметь возможность вызывать 'clearTimeout' на объекте после извлечения его из redis – user730569

+0

Я отредактировал ответ с примером – legege

+0

Я хочу, чтобы иметь возможность делиться им через экземпляры, поэтому в памяти на самом деле не было бы option – user730569

0

Этот код используется, когда тайм-ауты не должен быть стойкими через сервер перезагружается

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(); 
    }); 
}); 

Если вам нужен таймауты быть стойкими после перезапуска сервера, то вам может понадобиться для хранения _idleStart и _idleTimeout значения для каждого таймера в Redis, и загрузить их каждый раз при перезагрузке сервера

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

Вы теряете ссылку на объект объекта. – legege

+0

Мне нужно сохранить его на перезапуске сервера ... – user730569

+0

@ user730569 Это не сработает ... таймер исчезнет после перезагрузки. Вам нужно найти способ перенести их после перезапуска. Вы можете сохранить время начала и пересчитать значение тайм-аута при перезапуске. – legege

0

Я пытался сделать то же самое, что и ОП. Мое решение было установить тайм-аут с условной проверки на новый ключ внутри тайм-аут в своем обработчике разъединителя:

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); 

Затем, когда клиент снова подключается, я установил, что ключ к 0, поэтому материал, который нуждается обстрелять настоящий разрыв не происходит:

redis.hset("userDisconnecting:" + userId, "disconnect", 0); 

таймаутов сами не являются постоянными после перезапуска сервера, но вы можете решить, что, начав метод уборочной машины при запуске. Подключенные клиенты вернутся «в сети» довольно быстро.

Смежные вопросы