Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Error setting TTL index on collection #80

Closed
riston opened this Issue · 39 comments
@riston

I am using mongolab for hosting the sessions and the app is under the heroku host, some times the starting application gives the error.

**/node_modules/connect-mongo/node_modules/mongodb/lib/mongodb/connection/server.js:529
        throw err;
              ^
Error: Error setting TTL index on collection : sessions <MongoError: not authorized for query on herouku*****.system.indexes>

After going further it seems there is problem with executing the ensureIndex, does this get executed evert connect?

Or can this just be removed and be set from mongo shell ?

@hongkongkiwi

I've noticed that this happens when I try to do use the session immediately after starting the script (e.g. I try to connect immediately). If I give it 5 seconds it never happens.

In my case it gives this error:

Error: Error setting TTL index on collection : Sessions <Error: Cannot determine state of server>

I'm after a solution as I want to use this in a production environment.

@riston

Anyway, the error occurs in this code and the ensureIndex function takes too much time and gives TTL.

        self.db.collection(self.db_collection_name, function(err, collection) {
          if (err) {
            throw new Error('Error getting collection: ' + self.db_collection_name  + ' <' + err + '>');
          } else {
            self.collection = collection;

            // Make sure we have a TTL index on "expires", so mongod will automatically
            // remove expired sessions. expireAfterSeconds is set to 0 because we want 
            // mongo to remove anything expired without any additional delay.
            self.collection.ensureIndex({expires: 1}, {expireAfterSeconds: 0}, function(err, result) {
              if (err) {
                throw new Error('Error setting TTL index on collection : ' + self.db_collection_name + ' <' + err + '>');
              }

              callback && callback(self.collection);
            });

          } 
@AjmalSaid

same here.. and I also automatically opened the browser immediately after running the app (using "open"). after hours of invesitigation (in many directions^^) the timeout trick solved this problem. thx@andysavage

@jltwoo

I had similar issues whilst using mongoose connections and I did a bit of tracing all the way into the mongodb driver module so I just want to give some input to this.

Original app.js setup:

mongoose.connect("localhost", "test");
...
app.configure(function(){
  /* more config here...*/
  app.use(express.session({ 
    secret: "server_session_key"
    , store: new MongoStore({db: mongoose.connection.db })
  }));
})
...
// Start server
http.createServer(app).listen(app.get('port'), function() {
  console.log("Express server listening on port " + app.get('port'));
}); 

Problem with that is when MongoStore tries to perform ensureIndex in its constructor, mongoose is still in opening state. Since autoReconnect is by default true, the ensureIndex command gets queued up (more accurately it's the getIndexes command before ensureIndex that is used to prevent duplciates) and so it "fails" silently by design.

Core issue
It seems that the reconnect is not working properly with mongoose queued commands so they ultimately aren't executed (related issue,mongoose side) so we can randomly end up in a stale state depending on whether the mongoose connection was opened before MongoStore initializes (for most of my cases it's not).

First Workaround Attempt
Simply ensure mongoose is either connected first by using

mongoose.connect("localhost", "test", function(err){
 /*initialize MongoStore here...*/
});

Final workaround
First attempt didn't work for me since in my setup the MongoStore is initialized in app.configure and I don't want mongoose.connect placed there so what I end up is just pass in static parameters for MongoStore to connect on its own

var dbConfig = {
 "db": "test",
 "host": "localhost"
}

app.use(express.session({ 
 secret: server_session_key
 , store: new MongoStore(dbConfig)
}));

There are probably better ways, but the root problem is more related to mongoose and mongodb driver which is already tracked by others. Need to move on now.

Hope this helps.

@Naxmeify

Heyho, interesting workaround but my problem is that my mongoose connection goes over a admin Source Database like:

auth: 
  authSource: "admin"

How can i pass these options over connect-mongo?

Mongoose Like:

mongodb: 
    host: "localhost"
    db: "myDatabase"
    port: "27017"
    options: 
      user: "mongodb_other_user"
      pass: "my_impressive_mongodb_password"
      auth: 
        authSource: "admin"
@OliverJAsh

@hongkongkiwi Same issue here, [Error: Cannot determine state of server] (if I go into connect-mongo/lib/connect-mongo.js:162:23 and observe the Mongo error there).

@Naxmeify
mongoose.connect('mongodb://user:pass@host:27017/db?authSource=databaseName')
// or
mongoose.connect(uri, { auth: { authSource: 'databaseName' }})

3.6 Release Notes of Mongoose

@OliverJAsh

I'm not using this with Mongoose.

@OliverJAsh OliverJAsh referenced this issue from a commit in OliverJAsh/sbscribe
@OliverJAsh OliverJAsh Replace connect-mongo with connect-redis
May revert when this issue is fixed: kcbanner/connect-mongo#80
8c0cc4e
@chriswininger

I am passing in the db options so that the store can connect on it's own as described above, but I still frequently get the error, especially if I attempt to start a session too soon after spinning up the server.

@LinusU

This happens every time I hit the web server with a request before the connection to mongodb has been established.

@malixsys

Wait for the DB connection before starting your Express server:

var MongoStore = require('connect-mongo')(express);
var options = {url: ... };
var store = new MongoStore(options, function(ret) {
  // app.listen() here
});    
app.use(express.session({
  store: store
}));
@ramseydsilva

After breaking my head for ages the above did the trick for me!

@LinusU

Waiting with the .listen is a workaround but a quite bad one. The code in connect-mongo needs to be updated to wait for the connection to be established before trying to ensure indexes. Then this would be handled transparently and the server could start listening right away.

@malixsys

I agree, @LinusU, but you cannot have Mongo based sessions until the connection is established. Plus, it takes < 2 seconds and only at start up.
If you don't expect any client connections for which you would need sessions go ahead and don't wait for the connection for listening, but if you are experiencing the bug we are talking about here then you most probably are getting sessions trying to start before the db connection is established

@LinusU

I'm not suggesting that the session should be skipped. I would like connect-mongo to wait for the connection to be available, then ensure the index, then call next().

It wouldn't be a big difference from waiting to do .listen() but it doesn't require any special code from the user, and any request that dosen't need the session can go through. (e.g. static files, make sure to put app.use(express.static()) before app.use(session))

The biggest advantage is having the browser wait, instead of directly returning an error when you restart the server and then quickly reload the page. Very useful when developing.

@malixsys

Good points, it would probably be a good thing for MC to handle that. However, I do wonder where your DB sits, if it takes that long to connect?
Won't that pose a problem in dev productivity?
In any case, for me this is mostly rethorical as my DEV server restarts in ~200ms INCLUDING waiting for the connection. :)

@malixsys

Actually it's a bit longer now, but still no impediment to dev.

@LinusU

I don't really have a problem with it for two reasons. 1) It only happens when I'm really, really quick at reloading. (using nodemon to monitor for changes and then ⌘+S, ALT+TAB, ⌘+R). and 2) I use domain to handle all my incoming connections so I just get a nice 500 error page back at me, reload the page again and it will work.

Anyhow, it seems to be a problem for other people, and it should be an easy fix.

@jltwoo

@malixsys & @LinusU
I haven't had issues since 7 months from my last post about the workaround. But back then I observed that mongod startup does take a while only on windows' system after the system crashed and mongo was scanning through its journals, so this effect was observed more when I had pre-populated test data in my mongodb since the journals would be larger. Also I use replica sets so it takes a while for start up sometimes too. Therefore, creating the situation where it has to wait a bit longer, even just a few seconds.

Anyways I realized my lines of code references in my previous post are outdated. I see in the updated code that it checks for db.openCalled before going into the ensureIndex region. However, db.openCalled only indicates that db.open() is called but not state is connected (source code from node-mongodb-native) .

I dont have the time to dive in this longer again, but perhaps it's better to check that the connection object's connected property is true instead.

Note: this is based on my very initial read of the connect-mongo and node-mongodb-native code, haven't had time to test it out in runtime to see whether it is accessible. I just thought to give some input again since I realized how many others are interested in this issue.

@risseraka risseraka referenced this issue from a commit in risseraka/connect-mongo
@risseraka risseraka fix: quick and dirty, refs #80 d3ccd19
@mattdeluco

I've been running into this issue recently while running unit tests in my project. It's odd though, with one test suite it happens, with the other it doesn't. I haven't been able to pinpoint the difference.

@mattdeluco

When setting up my express app to use express-session with a connect-mongo store, if I use "mongoose_connection: db.connection" (where db is an instance of Mongoose) instead of "db: db.connection.db", I don't get the TTL error.

@malixsys

@outrightmental Maybe I missed something, but I don't see how that differs from my solution..

@malixsys

Sorry @outrightmental, did not mean it that way, thought something new had come out :)

@outrightmental

For sure! That's how we keep these threads useful; open source is pure karma :)

@focusaurus

:+1: Also seeing this in a node-mongodb-native/express app. Getting a fix in place would be nice.

@malixsys

@focusaurus do you wait for the connection before app.listen() ?

@focusaurus

No, and honestly I'd rather not because I'd rather serve my users an error page saying "down for maintenance" or similar instead of them getting a refused connection and an unfriendly browser error page. It's not causing me real production problems though, but I've seen it in development.

@malixsys

@focusaurus True! Although, that is just at start up and a few seconds, prior to which, your server WAS down...

@nylen nylen referenced this issue from a commit in nylen/node-web-media-player
@nylen nylen Work around an error with MongoDB sessions ceb28dc
@techjeffharris techjeffharris referenced this issue from a commit in techjeffharris/connect-mongo-ttl-error-example
@techjeffharris techjeffharris reproduces kcbanner/connect-mongo#80 - see error.log 901e041
@techjeffharris

@jdesboeufs, in response to your request in #119 I was able to recreate the error with code found here.

Check out error.log (my console history)

I had debug running and was using nodemon, so there are some times listed. let me know if you need any more info!

@jdesboeufs
Collaborator

@techjeffharris Can you try with the upcoming version? (master)

@jdesboeufs
Collaborator

I'm not able to reproduce your issue :(

@malixsys

@techjeffharris you are waiting for Mongoose's connection, not Mongostore, try:

var MongoStore = require('connect-mongo')(express);
var options = {url: ... };
var store = new MongoStore(options, function(ret) {
// app.listen() here
});

app.use(express.session({
store: store
}));

@jdesboeufs
Collaborator

Since v0.5.0 MongoStore take care of that.
And callback in constructor has been removed ;)

@malixsys

Ceci explique cela?

@jdesboeufs
Collaborator

I don't know. @techjeffharris is using ~0.4.1 -> 0.4.2.
But if you are right, this issue may have been fixed with 0.5.0.

@nylen nylen referenced this issue from a commit in nylen/node-web-media-player
@nylen nylen Upgrade connect-mongo to v0.5.x
v0.5.x should resolve kcbanner/connect-mongo#80, see discussion there
for details.
b17b003
@nylen nylen referenced this issue from a commit in nylen/node-web-media-player
@nylen nylen Upgrade connect-mongo to v0.5.x
v0.5.x should resolve kcbanner/connect-mongo#80, see discussion there
for details.
2f42828
@techjeffharris

I have been really busy with my day-job, sorry!

@malixsys, I have been under the impression that MongoStore only needs a callback if the mongo/mongoose connection has not initialized. You're saying that I need to use a callback for MongoStore even if my db connection is open?

@jdesboeufs, if I upgrade to connect-mongo:master, this issue should theoretically be resolved? A lot has changed, so I want to get up-to-date instructions before I check resolution :)

Thanks for all your hard work!

@malixsys

@techjeffharris I use a callback to wait for the DB connection before starting my server.listen() so that the store does not try to create indexes too soon...

@jdesboeufs
Collaborator

@malixsys Using a callback must now be avoided since connect-mongo will wait for the database connection.

@techjeffharris You can upgrade to 0.5.3, mongoose support has been improved and I need feedback :)

@jdesboeufs jdesboeufs modified the milestone: 1.0.0
@jdesboeufs jdesboeufs closed this
@techjeffharris

@jdesboeufs Sorry, I have been busy with a side project.. I'll cross my fingers and open a new issue if I run into problems :) Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.