-
-
Notifications
You must be signed in to change notification settings - Fork 987
Split MemoryStore in a separate module + avoid memory leaks #487
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add Node.js 0.8 support if you want to land this here :) Also please revert the version bump from the PR; the version bump is part of the release process.
|
This reverts commit 7f5485e.
An additional item I noticed is that the exported MemoryStore in this library never mutated the passed-in |
I'm adding v0.8.28 support to memorystore but I'm not sure why it's failing. On my computer ci tests are running smooth. |
It looks like the module may have some variable & handle leaks. I pushed up a change to the
The |
test/session.js
Outdated
it('should count all entries in the store', function(done){ | ||
var store = new session.MemoryStore() | ||
var k = 10 | ||
i = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the source of the i
global leak.
ok thanks. Found, it was a missing local declaration. |
haha, looks like we both found it :) I also just fixed the leak checks so they actually work on Travis CI -- I added them as argument to |
eheh yeah ;) great! So what are you suggesting for the |
At least the reason it is failing on Travis CI is because
I usually just use the pattern that this module uses, which is that all the variables are extracted out of the object, and defaults are set at extraction time. That ends up supporting two use-cases I see at once: frozen objects where you cannot modify them and object re-use, where users will pass that object around / modify it after giving it to your module and are not expecting modification. It's also much faster than cloning, especially since users also expect that they can use inherited properties and most cloning only takes into account own keys. |
Could this work? options = options || {}
Store.call(this, options)
this.options = {} // < -- instead of options || {}
this.options.checkPeriod = options.checkPeriod || oneDay
this.options.max = options.max || Infinity
this.options.ttl = options.ttl
this.options.dispose = options.dispose
this.options.stale = options.stale
this.options.noDisposeOnSet = options.noDisposeOnSet |
We should consider upgrading just the CI npm client when executing the test under Node 0.8. We should really consider it, like the guys of underscore did here. |
README.md
Outdated
@@ -35,8 +35,7 @@ and writes cookies on `req`/`res`. Using `cookie-parser` may result in issues | |||
if the `secret` is not the same between this module and `cookie-parser`. | |||
|
|||
**Warning** The default server-side session storage, `MemoryStore`, is _purposely_ | |||
not designed for a production environment. It will leak memory under most | |||
conditions, does not scale past a single process, and is meant for debugging and | |||
not designed for a production environment. It does not scale past a single process, and is meant for debugging and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dougwilson I believe you wanted the README to be 80 character wrap?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea
Yep, that would work :)
We purposely only test against the version of npm that was included in the version of Node.js at the time. If we do decide that it needs to be higher, we should list a minimum version in the |
package.json
Outdated
@@ -15,6 +15,7 @@ | |||
"crc": "3.4.4", | |||
"debug": "2.6.8", | |||
"depd": "~1.1.0", | |||
"memorystore": "~1.2.4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the ~
from the version here; the third-party deps are always exact versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just FYI the pull request continues to fail across all Node.js versions because this change is introducing a handle leak, preventing the event loop from shutting down properly.
It looks like this replacement contains a breaking change to the |
The
|
Sure, but that would immediately break anyone who is today using the |
Looks like I just documented it wrong when I added the docs; the implementation existed for a very long time before the docs were added. The doc issue looks to have been an oversight, we can fix the docs :) |
Alright, fixing it right now, btw are all the contributors' store modules being using Array or Object? :) PS. I'm also trying to investigate who's causing the handle leak. |
I'm not sure, because there are a lot to look through. I would assume they are using Array since that is the only form that was ever documented. You can also use Array in your module too, it's only since you're trying to actually replace the existing MemoryStore that makes it matter. If your module is just listed with the others, then it really doesn't matter. Another bug I just found is that the session data in your store is not getting serialized and/or cloned between requests. This means that the exact same object reference is given to multiple requests, and mutating the object in out requests causes another request that is happening in parallel to also mutate. This is not an issue in the current MemoryStore, though. Please take a look at fixing that :) |
Another issue I just found is that the store is not honoring the I'm running your module inside a product app right now to help smoketest the rewritten implementation. I'll report if I find anything else. |
As regards the // connect-redis
RedisStore.prototype.touch = function (sid, sess, fn) {
var store = this;
var psid = store.prefix + sid;
if (!fn) fn = noop;
if (store.disableTTL) return fn();
var ttl = getTTL(store, sess);
debug('EXPIRE "%s" ttl:%s', sid, ttl);
store.client.expire(psid, ttl, function (er) {
if (er) return fn(er);
debug('EXPIRE complete');
fn.apply(this, arguments);
});
}; and this is my // memorystore
MemoryStore.prototype.touch = function (sid, sess, fn) {
var store = this.store
var ttl = getTTL(store, sess, sid)
debug('EXPIRE "%s" ttl:%s', sid, ttl)
store.set(sid, store.get(sid) || sess, ttl)
fn && defer(fn, null)
} |
I'm only comparing this to the |
Could the handle leak be related to coveralls pheraps? Edit: I can't reproduce it on a separate branch with travis too :') The build now worked. It could easily be a flaky Travis issue. Btw can you share/add some test for the |
I'm traveling right now so cannot take a close look, but I guarantee you the leak is real. Tou can see I wrote about it way above, showing it on my own machine. Likely the reason you are not seeing it locally is because yiur branch does not contain the check I added to master to show the issue :) I noted above I pushed a change to master so the test suite would now catch variable and handle leaks. You need to fix the handke leak in your code. I will add a twst case when I get back late next week for ya. |
ops, I didn't notice your commit with the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please wrap the README.md to 80 characters
README.md
Outdated
@@ -35,8 +35,7 @@ and writes cookies on `req`/`res`. Using `cookie-parser` may result in issues | |||
if the `secret` is not the same between this module and `cookie-parser`. | |||
|
|||
**Warning** The default server-side session storage, `MemoryStore`, is _purposely_ | |||
not designed for a production environment. It will leak memory under most | |||
conditions, does not scale past a single process, and is meant for debugging and | |||
not designed for a production environment. It does not scale past a single process, and is meant for debugging and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please wrap at 80 characters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
I still think that we should just list your module with the others and add a note up at the top with the production warning instead of actually replacing our implementation. I'm not sure if even adding this module as our dependency is going to work out in the long run, as just in the course of this pull request the module has made several breaking changes without any major version bumps, a violation of semver. I assume that that means this is not a semver-compliant module, which isn't something we really want to depend on. Here is what my proposal is, summarizing a few previous comments above:
Then as a separate step, we can deprecate users not providing a Even the
So re-enforcing that the users should be creating a memory store instance themselves and passing it to the I hope this makes sense. What do you think @gabeio ? |
Sounds good to me. Having as few dependencies as possible is very nice. It especially sounds like a good idea to deprecate the in memory database on this module (and eventually remove it). |
Ok but just consider that this module is written in a way that doesn't break things. It's compliant with the old MemoryStore APIs and behaviour right now. Tests should be written to prove this at least and all the checks passed. |
Right, but that has nothing to do with the proposal above.
But we don't want to have any store be part of this module at all. Just like Express dropped including all middleware in 4.0. |
Previous PRs improving the MemoryStore never landed because we don't want to improve it and just want it gone. This is going in the opposite direction we really want, and @gabeio agrees. I think that we should go down the proposed route above to direct users to your module harder and get the MemoryStore removed from our code base. We never removed the MemoryStore module from our code base partly because until now, there was no store module to direct those users to, but now hat you made |
ok that's clear, it make sense. Let's summerize the next steps then. :) If |
Right, if your module is just listed with the others, then it really doesn't matter. Supporting Node.js 0.8 was only necessary if it was a dependency of this module. Being free to choose what Node.js versions you want to support is one of the nice things about not being a dependency. This was one of the same reasons middleware was removed in Express 4. |
Ok, so I could revert the commits or better open another PR with the warning mex and the updated documentation. What do you think? |
Either one is fine. You're welcome to continue to use this PR |
I haven't heard back in a while, so I went ahead and (for now) added the |
Sorry for my late response. Thanks for all the hard work. |
This PR addresses both #128 and #220.
The new module is fully-tested and makes use of the awesome lru-cache.