-
Notifications
You must be signed in to change notification settings - Fork 343
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
Fix merging bug in 6.1.0 that resulted in sessions being deleted. #348
Conversation
This library is fairly battle tested and handles the many edge cases when it comes to merging objects deeply in JS.
@zkldi thanks for looking deeply into this. Can you fix up the failed checks please? @apydo not sure if you'd be willing/able, but since you could replicate the issue before, I wonder if you'd be able to test your workflow and see if this PR fixes the issue you were having with v6.1.0? |
Pushed a fix for the formatting! |
@wavded, I'll be able to make some tests next monday, not before. Sorry. |
Not sure why the tests are failing, not entirely sure what they're doing either... |
@wavded , I made several quick tests in the same way I did it last time and I cannot see any error while authenticating in page and launching several quick ajax calls within a second. |
Thx @apydo for taking the time to check this out. @zkldi you can pull the test changes from the original PR introducing this feature. That "should" fix them -> https://github.com/tj/connect-redis/pull/333/files |
Backported those changes -- hopefully I got all of that right? Not the best git user 😅 |
any update on this PR? |
Thx @fillon, this had slipped my mind, it has been released now! |
After upgrading from 6.1.1 to 6.1.2 this morning, I've noticed tests in my automated test suite failing intermittently. I'll run the entire test suite once and 1% of the tests will fail and I'll run the entire test suite again and a different 1% of the tests will fail. I'm using I'm still investigating the issue, but I'm fairly confident I've isolated the issue to 6.1.2 of |
That's not good, the 6.1.2 patch was intended to fix this bug in (deprecated) 6.1.0. I'll crack a look at it now. I'm pretty confident this should work though, since I tested it for a while. |
Cursory glance shows that there's another timing issue in the original 6.1.0 code, since Maybe we'll have to revert back to pre-6.1.0 again until this can be properly investigated. I also can't reproduce the issue yet, but since this is a patch fix this potentially broken code is currently propogating across the ecosystem. ouch. |
Is this related #354 ? https://github.com/uktrade/data-hub-frontend/blob/a87c30333a63533fe148f4c84d3a7b6c5e13e756/src/middleware/session-store.js#L7 this is how we're using it in production. |
This has been reverted. |
yeah, ugh. Sorry about this. I think there might be some other unrelated bugs in the 6.1.0 update, but my testing didn't catch any of this. |
No worries. Appreciate the time you took to look into it. I think we may need to give this feature a rest until we can get something rock solid. Want to keep releases stable. |
Just my $0.02 - I’m not convinced this feature will work as designed, unless there is a way to provide users the ability to atomically lock the session when they modify its contents. It’s ok if a request just reads the data, but if there is any read, change of contents followed by a write back to redis this whole block needs to be protected by a lock to prevent concurrency issues. The way I’ve implemented this with redis in the past is by creating an empty key alongside the session suffixed with Ideally, the session is only ever written once. WORM - write-once-read-many, and then you can avoid locking entirely. Potentially for session expiry another key could be created suffixed with |
In terms of the session getting huge in our production environment. We were seeing our permissions array, which just contains a list of strings of permissions the user has, get the permissions repeated thousands of times. Maybe the deepMerge just duplicates them? |
Oh, this is a default feature of the deepmerge library and can trivially be changed. |
I'm not sure merging conflicting sessions a good idea. Aside from Either:
If they can be locked, perhaps it should be possible to also request a session in read only mode that could be a long running (eg file upload) request but that is not saved at the end of the session. |
This PR fixes the bug in 6.1.0 without reverting the commit that added the functionality.
Rundown
0fbca57#diff-759b3934f9097285185078895a48275b1a0b0221852ad264a4a2e2dc67b24430R207-R222
This function here does not merge dates properly. Instead, it replaces any merging instances of a date with an empty object. This appears as a race condition because
mergeDeep
is only called sometimes based on timestamps -- which is why the bug triggers more reliably when a page loads and a lot of ajax calls are made.Of course, when
expires
gets set to an empty object instead of a date, whenever math is performed on it, it turns intoNaN
, andNaN > 0
is false, so all sessions get immediately thrown away.This is emphatically not a bug in
express-session
, but I did get sent on a wild goosechase by its logic 😅.The correct fix here is to replace
mergeDeep
with a function that properly merges dates. I'm usingdeepmerge
here, because it's pretty battle tested.