High Availability Redis Session with Express

Recently we have needed update our session solution with Redis to use Redis as a cluster, increasing the availability of our sites in the event that we have to cycle our Redis servers.

High Availability Redis Session with Express

Recently we have needed update our session solution with Redis to use Redis as a cluster, increasing the availability of our sites in the event that we have to cycle our Redis servers.

The current solution connect to a single Redis service, however we can not update that system because it'll take down systems that are dependent on that system. Yes, this is very bad practice, and this is why we are now addressing it.

The solution moving forward is to create a cluster of Redis servers using Redis Sentinel (that setup is outside the scope of this post). We then need to update our systems to use sentinel as a client instead of connecting directly to Redis.

To do this, we needed to change from using Redis module to create a client to using the redis-sentinel module. Because sentinel returns a Redis Client as if I was manually creating one from the redis module, the update was simply to swap out Redis clients. We went from this

// app.js
const express = require("express"),
    app = express(),
    session = require("express-session"),
    redisStore = require("connect-redis")(session),
    redis = require("redis"),
    redisClient = redis.createClient({
        host: "...",
        port: 6379
    });

//...

app.use(session({
    secret: "...",
    store: new redisStore({
        client: redisClient,
        ttl: 900
    })
}));

//...

to this

// app.js
const express = require("express"),
    app = express(),
    session = require("express-session"),
    redisStore = require("connect-redis")(session),
    sentinel = require("redis-sentinel"),
    sentinelMaterName = "mymaster",
    sentinelEndpoints = [
        { host: "...", port: 26379 },
        { host: "...", port: 26379 },
        { host: "...", port: 26379 }
    ]
    redisClient = sentinel.createClient(sentinelEndpoints, sentinelMaterName);

//...

app.use(session({
    secret: "...",
    store: new redisStore({
        client: redisClient,
        ttl: 900
    })
}));

//...

Upon testing, we have found that the system will fail over gracefully, though it will throw an error into the express error handler when swapping masters. We setup out systems to handle that error by reloading the page. The system will hold all requests until it establishes a new Redis connection.