5

I'm using redis for storing my sessions in expressjs. It works fine when running locally and even works most of the time when deployed on heroku. The problem is that regularly (when deployed on heroku) I see my session updates being lost.

e.g. a user logs in to my website, and I add their user object to the session:

req.session.user = user;

however (sometimes) when I try and retrieve the object moments later (in a different request) it isn't there

//sometimes this is empty, even though I've just set it
var currentUser = req.session.user;

I initialise the session store as follows

if (process.env.REDISTOGO_URL) {
    console.log('Connecting to redis:' + process.env.REDISTOGO_URL);
    var rtg = require('url').parse(process.env.REDISTOGO_URL);
    var redis = require('redis').createClient(rtg.port, rtg.hostname);
    redis.auth(rtg.auth.split(':')[1]);
} else {
    console.log('Connecting to local redis');
    var redis = require('redis').createClient();
}

//sessions
app.use(express.cookieParser('secret key for cookie monster')); //used by session
var RedisStore = require('connect-redis')(express);
app.use(express.session({
    store: new RedisStore({
        client: redis
    })
}));

Any ideas? Do I need to do some kind of flushing (or explicit saving) of the session data?

Tom G
  • 2,025
  • 3
  • 21
  • 32
  • 'moments later', are you sure that this moment is after the previous request has completed? – TruongSinh Jan 22 '14 at 18:01
  • Definitely, yes, because my login logic doesn't load the next page until it finishes. Thanks for the idea though – Tom G Jan 23 '14 at 09:36

1 Answers1

0

I'm going to hijack this ancient question and let you guys in on how I solved the problem.

TL;DR

You have probably copied the REDIS_URL value from your Heroku app config to your local .env file some time ago. Heroku changes that value over time and that has now actually happened.

The solution is to copy the new REDIS_URL value from your Heroku app config to your local .env file or use another Redis instance for local development.

What you probably already tried

Probably your sessions were working a few days ago and you tried and verified all the usual suspects in order to fix this sudden problem.

All to no avail. Finally, when you remove the RedisStore bit from the session config, sessions are working again.

const session = require('express-session');
const RedisStore = require('connect-redis')(session);
// ...
server.set('trust proxy', 1);
server.use(
    session({
        // store: new RedisStore({
        //     url: process.env.REDIS_URL,
        // }),
        secret: process.env.SESSION_SECRET,
        resave: false,
        saveUninitialized: true,
        cookie: {
            path: '/',
            httpOnly: true,
            secure: false,
            maxAge: null,
        },
    })
);

What's happening?

Sometime later I understood how removing the Redis store solved the problem. I was using a REDIS_URL in my local .env file that was provided by my Heroku app config. And I learned that the REDIS_URL on the Heroku app may change over time.

In order for Heroku to manage this add-on for you and respond to a variety of operational situations, the REDIS config vars may change at any time. Relying on the config var outside of your Heroku app may result in you having to re-copy the value if it changes.

(emphasis mine)

So in my case that had actually happened and my local .env file still had the old REDIS_URL value. In effect, the session store could not be created, because it tried connecting to a service that isn't there. That's why removing RedisStore and thus falling back to the default MemoryStore fixed the problem.

Prevent reoccurrence

I created an account at redislabs.com and created a free Redis instance. That url I now use in my local .env file. That url doesn't change (I hope).

Christiaan Westerbeek
  • 10,619
  • 13
  • 64
  • 89
  • Not sure how removing the Redis store solves the problem, though. Now you're just using the default MemoryStore, which leaks memory and doesn't scale beyond a single dyno. – Devin Jul 10 '19 at 17:24
  • I was using a REDIS_URL in my local .env that was provided by my Heroku app config. But that URL on the Heroku app actually changes over time. My local .env file still had the old REDIS_URL, so the session store could not be created. That's why removing RedisStore and thus falling back to default MemoryStore fixed the problem. I will update my answer later to reflect this finding. – Christiaan Westerbeek Jul 10 '19 at 17:32
  • I've rewritten my answer – Christiaan Westerbeek Jul 10 '19 at 17:51