For an application I'm developing, I'm planning to not only read from my cache, but also to write data updates into it (for data that is changed very frequently). For this to properly work however, I need to be able to handle an event of the key/data expiring so that it is saved to my database when not tweaked for a while.
I have tried playing around with redis.psubscribe() and redis.on('pmessage'), but no such solutions seem to be doing anything (other than hooking it up to the same client as the one I'm setting/getting data with, which returns an error).
Is there an up-to-date way to handle expiry in (io)redis (nodejs)?
You can use keyspace events to listen for key expiring events, you need two distinct channels one for publishing events (main channel) and another one to listen for expiring events, the default behavior of Redis is to only return the key of the element that expired in the expiring event message, a workaround this can be found here, the following is a simple implementation using that workaround:
import Redis from 'ioredis';
const subscribeChannel = new Redis({
host: 'localhost',
port: '6379',
db: 0,
});
const publishChannel = new Redis({
host: 'localhost',
port: '6379',
db: 0,
});
function set(channel, key, value, seconds){
channel.set(key, value);
// use shadowkey to access the value field on the expire event message
channel.set(`${key}:${value}`, '');
// set expire time on shadowkey
channel.expire(`${key}:${value}`, seconds);
}
publishChannel.on('ready', () => {
// configure keyspaces event and specify expiring events with "Ex"
publishChannel.config("SET", "notify-keyspace-events", "Ex");
// subscribe to the
subscribeChannel.subscribe("__keyevent@0__:expired");
// listen for expiring event messages
subscribeChannel.on('message', async(channel, message) => {
// retrieve key and value from shadowkey
const [key, value] = message.split(":");
// store value in the main storage
db.insert(value);
// delete actual value from the redis store
publishChannel.del(key);
});
// set "value" with "key" and set it to expire after 10 seconds
set(publishChannel, "key", "value", 10);
});