Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to receive Redis expire events with node?

Tags:

node.js

redis

ttl

I want to listen the expire events from Redis. I've configured on my redis.conf the notify-keyspace-events "AKE" and this is my code on node:

const redis = require('redis');
const client = redis.createClient();
const subscriber = redis.createClient();
const KEY_EXPIRING_TIME = 10; // seconds

client.setex('myKey', KEY_EXPIRING_TIME, 'myValue');

subscriber.on('message', function(channel, msg) {
  console.log( `On ${channel} received ${msg} event`);
});

subscriber.subscribe('myKey', function (err) {
  console.log('subscribed!');
});

What I hope is to see in 10 seconds that the event is triggered. The setex command works correctly, in 10 seconds the key is not in the database, I have the problem when I try to capture the event.

What am I doing wrong?

like image 411
emilioriosvz Avatar asked Feb 03 '17 15:02

emilioriosvz


People also ask

How does Redis integrate with node js?

Create new session. js file in the root directory with the following content: const express = require('express'); const session = require('express-session'); const redis = require('redis'); const client = redis. createClient(); const redisStore = require('connect-redis')(session); const app = express(); app.

How does Redis expiration work?

When a key has an expire set, Redis will make sure to remove the key when the specified amount of time elapsed. The key time to live can be updated or entirely removed using the EXPIRE and PERSIST command (or other strictly related commands).

How do I change the expiration date on Redis cache?

To create a Redis with an expiration time, use the SET command and the EX option to set the expiration time. The EX option takes a number in seconds and sets the number of seconds the key is valid until expiration. You can also use PX to specify the expiration time in Milliseconds.


2 Answers

It is in fact possible to listen to the "expired" type keyevent notification using a subscribed client to the specific channel ('__keyevent@db__:expired') and listening to its message event.

no need for setInterval / setTimeout or additional libraries

Proof-of-concept (working : tested with NodeJS v.9.4.0)

const redis = require('redis')
const CONF = {db:3}
var pub, sub
//.: Activate "notify-keyspace-events" for expired type events
pub = redis.createClient(CONF)
pub.send_command('config', ['set','notify-keyspace-events','Ex'], SubscribeExpired)
//.: Subscribe to the "notify-keyspace-events" channel used for expired type events
function SubscribeExpired(e,r){
 sub = redis.createClient(CONF)
 const expired_subKey = '__keyevent@'+CONF.db+'__:expired'
 sub.subscribe(expired_subKey,function(){
  console.log(' [i] Subscribed to "'+expired_subKey+'" event channel : '+r)
  sub.on('message',function (chan,msg){console.log('[expired]',msg)})
  TestKey()
 })
}
//.: For example (create a key & set to expire in 10 seconds)
function TestKey(){
 pub.set('testing','redis notify-keyspace-events : expired')
 pub.expire('testing',10)
}
like image 115
EMX Avatar answered Sep 17 '22 07:09

EMX


Approach 1:-

The setInterval function has to be used to check whether the value is expired periodically. I am aware that this is not equal to listening to events. However, it serves the purpose indirectly.

The below code checks the value for every 5 seconds.

const redis = require('redis');
const client = redis.createClient();
const subscriber = redis.createClient();
const KEY_EXPIRING_TIME = 10; // seconds

var args = ['myKey', KEY_EXPIRING_TIME,  'myValue'];


client.setex('myKey', KEY_EXPIRING_TIME, 'myValue');

subscriber.on('message', function(channel, msg) {
  console.log( `On ${channel} received ${msg} event`);
});

subscriber.subscribe('myKey', function (err) {
  console.log('subscribed!');
});

setInterval(function() {  
  client.get('myKey', function(err, value) {
    if (err) {
      throw err;
    }
    if (value) {
      console.log('value:', value);
    }
    else {
      console.log('value is gone');
      process.exit();
    }
  });
}, 5e3);

Approach 2:-

The redis-notifier can be used to listen to the events. However, it requires Python >= v2.5.0 & < 3.0.0 in order to install this package.

redis-notifier

var RedisNotifier = require('redis-notifier');

var eventNotifier = new RedisNotifier(redis, {
  redis : { host : '127.0.0.1', port : 6379 },
  expired : true,
  evicted : true,
  logLevel : 'DEBUG' //Defaults To INFO 
});

//Listen for event emission 
eventNotifier.on('message', function(pattern, channelPattern, emittedKey) {
  var channel = this.parseMessageChannel(channelPattern);
  switch(channel.key) {
    case 'expired':
        this._handleExpired(emittedKey);
      break;
    case "evicted":
      this._handleEvicted(emittedKey);
      break;
    default:
      logger.debug("Unrecognized Channel Type:" + channel.type);
  }
});
like image 39
notionquest Avatar answered Sep 18 '22 07:09

notionquest