Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Session Undefined - Using Connect-Redis / ExpressJS / Node

This morning I awoke to find Nodejitsu spinning out the following error:

Warning: connection.session() MemoryStore is not designed for a production environment, as it will leak memory, and will not scale past a single process.

'Well then!' I thought to myself - and off I went to find something more suitable. I settled on Redis, and immediately began implementing connect-redis and node-redis into my application.

However, the following error continues to surface after repeated attempts at a fix. The error is as follows:

TypeError: Cannot set property 'loggedIn' of undefined
        at /Users/Ryan/Aggregus/server.js:300:25
        at Promise.<anonymous> (/Users/Ryan/Aggregus/object_models/user.js:60:5)
        at Promise.<anonymous> (/Users/Ryan/Aggregus/node_modules/mongoose/node_modules/mpromise/lib/promise.js:162:8)
        at Promise.EventEmitter.emit (events.js:95:17)
        at Promise.emit (/Users/Ryan/Aggregus/node_modules/mongoose/node_modules/mpromise/lib/promise.js:79:38)
        at Promise.fulfill (/Users/Ryan/Aggregus/node_modules/mongoose/node_modules/mpromise/lib/promise.js:92:20)
        at /Users/Ryan/Aggregus/node_modules/mongoose/lib/query.js:1813:13
        at model.Document.init (/Users/Ryan/Aggregus/node_modules/mongoose/lib/document.js:243:11)
        at completeOne (/Users/Ryan/Aggregus/node_modules/mongoose/lib/query.js:1811:10)
        at /Users/Ryan/Aggregus/node_modules/mongoose/lib/query.js:1779:11

loggedIn is simply referring to req.session.loggedIn, a session variable I use to track logged-in users. The following is the application code in question:

var express = require('express');
var crypto = require('crypto');
var mongoose = require('mongoose');
var nodemailer = require('nodemailer');
var request = require('request');
var underscore = require('underscore');
var mandrill = require('node-mandrill')('0bFNPDenlDiZtu7aXujDQQ');
var connect = require('connect');
var engines = require('consolidate');
var fs = require('fs');
var redis = require("redis").createClient();

var RedisStore = require('connect-redis')(express);

var sessionStore = new RedisStore({
    client: redis
});

var stripe_api_key = 'KEY';
var Stripe = require('stripe')(stripe_api_key);

var app = express(); 

app.configure(function() {
    app.engine('html', engines.jade);
    app.set('view engine', 'html');
    app.use(express.cookieParser()); 
    app.use(express.bodyParser());
    app.use(express.session({secret: "svtabyrki4q786as37c785ta8vi56aiw4i8w467acv", store: sessionStore}));
    app.use(express.static(__dirname + '/www'));
    app.use(express.compress()); 
    app.use(app.router);

});

// Mongoose Connection

var db = mongoose.connection;

var dbURI = 'HIDDENURL';

db.on('disconnected', function() {
    mongoose.connect(dbURI, {server:{auto_reconnect:true}});
});

db.on('error', function(error) {
  console.error('Error in MongoDb connection: ' + error);
  mongoose.disconnect();
});

mongoose.connect(dbURI, {server:{auto_reconnect:true}});

// Mongoose Object Models

var User = require('./object_models/user')(mongoose, nodemailer, mandrill);
var Notifications = require('./object_models/notification')(mongoose, nodemailer);
var Experience = require('./object_models/experience')(mongoose, nodemailer);
var Booking = require('./object_models/booking')(mongoose, nodemailer);
var Review = require('./object_models/review')(mongoose, nodemailer);
var Heart = require('./object_models/heart')(mongoose, nodemailer);
var Message = require('./object_models/message')(mongoose, nodemailer);

// Nodemailer Settings

var smtpTransport = nodemailer.createTransport("SMTP",{
    service: "Gmail",
    auth: {
        user: "[email protected]",
        pass: pwd
    }
});

// Bootstrap Call

app.get('/', function(req, res) {
    res.render('../index.html');
    console.log("WUSUP");
});

To provide further clarity, here is what I have tried up until this point to no avail:

  1. I have placed app.use(express.cookieParser()); prior to the express.session call, as most articles of this subject suggested.
  2. I have ensured that my new RedisStore call references the client directly upon initialization.
  3. I have placed app.use(app.router) after both the init calls for both express.session and 'express.cookieParser'.
  4. My Redis server is fully functional, via the createClient() call.

This similar question was resolved by preventing a rather insignificant app.use initialization to call app.router prior to Express' sessionStore being initialized.

Thus, TL;DR: In using connect-redis, my session variables return undefined. I have scoured the web for answers, and my only clue would be that app.router is being started prior to Express' own session handling. Where that little glitch occurs is beyond me. Gods of Stack Overflow have mercy on my poor soul.

Edit: Thought a package.json might be handy for reference. Generated via NodeJitsu:

{
  "name": "Aggregus",
  "subdomain": "aggregus-Aggregus",
  "scripts": {
    "start": "node server.js"
  },
  "version": "0.0.0-14",
  "engines": {
    "node": "0.8.x"
  },
  "dependencies": {
    "connect": "2.7.8",
    "consolidate": "0.9.1",
    "express": "3.2.2",
    "jade": "0.30.0",
    "mongoose": "3.6.9",
    "node-mandrill":"1.0.1",
    "nodemailer": "0.4.1",
    "request":"2.22.0",
    "stripe": "1.3.0",
    "underscore":"1.4.4"
  }
}
like image 620
Ryan Miller Avatar asked Jul 11 '13 17:07

Ryan Miller


1 Answers

You're calling connect-redis wrong, and you don't need redis installed separately. However, I don't see connect-redis in your package.json, so you should npm install --save connect-redis. Then do something like this:

var express = require('express');
var RedisStore = require('connect-redis')(express);
var ports = require('./classes/ports.js');
var config = require('./config/config.js');
var routes = require('./routes');
var errors = require('./classes/errors.js');

var app = express();
ports(app);
app
.use(express.logger())
.use(express.compress())
.use(express.cookieParser())
.use(express.session({
  store: new RedisStore({
    port: config.redisPort,
    host: config.redisHost,
    db: config.redisDatabase,
    pass: config.redisPassword
  }),
  secret: 'Your secret here',
  proxy: true,
  cookie: { secure: true }
}))
.use(express.favicon(__dirname + '/../public/img/favicon.ico'))
.use(express.bodyParser())
.use(express.methodOverride())

routes(app);
errors(app);
like image 179
Dan Kohn Avatar answered Nov 13 '22 09:11

Dan Kohn