-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Framework: build redux store from scratch if persisted data is too old #3271
Conversation
@@ -55,7 +72,7 @@ function loadInitialStateFailed( error ) { | |||
|
|||
function persistOnChange( reduxStore ) { | |||
reduxStore.subscribe( function() { | |||
localforage.setItem( 'redux-state', serialize( reduxStore.getState() ) ) | |||
localforage.setItem( 'redux-state', addTimestamp( serialize( reduxStore.getState() ) ) ) |
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.
The addTimestamp
/removeTimestamp
calls could maybe be moved inside the serialize
/deserialize
functions, making this line a little simpler?
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.
👍 added in e57ad3f
Interested in how the 7 day figure was arrived at? |
Bootstrapping is still working fine on this branch 👍 |
@@ -16,6 +17,8 @@ import config from 'config'; | |||
*/ | |||
const debug = debugModule( 'calypso:state' ); | |||
|
|||
export const MAX_AGE = ms( '7 days' ); |
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.
I'm all for leveraging dependencies, but this seems a bit... overkill? 😄 Can't we just calculate this in advance and leave a comment // 7 days
?
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.
Perhaps something like this is clear enough?
const MAX_AGE = 7 * 24 * 60 * 60 * 1000;
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.
Perhaps something like this is clear enough?
Not very clear to me 😄
I'd suggest:
const MAX_AGE = 604800000; // 7 days
Or if you think it's important to explain the conversion:
const MAX_AGE = 604800000; // 7 days = 7 * 24 * 60 * 60 * 1000
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.
It's nice on the PHP side of things because we use constants that are easily searchable
const MAX_AGE = 7 * DAY_IN_HOURS * HOUR_IN_MS
or something like that. different here because of the s
vs ms
thing
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.
Thanks for the suggestions! I'll update with some constants. The problem with simply adding a comment is that they can get out of sync with the value, which is why I added in the micro lib. I've used it in the past where folks were tired of redefining constants in separate files.
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.
Updated in e57ad3f
I think an ideal mechanism would be for the expiration to apply to individual segments of the state tree, not the entire tree. It'll be a bit abrupt that if my next session happens to fall on the lapse date, everything known in the persisted store is forgotten. Especially concerning if we're relying on this behavior in the desktop app to provide an offline experience if a user launches it without network connectivity (correct me if this is not a goal of persistence). Another preference might be towards the store initialization not managing the expiration of items, but rather the reducer perform its own clean-up in receiving new data. So rather than risk objects ever being deleted during startup, they'd only be cleaned up as new items are received. That said, I think this would be a fine direction for a short-term solution to the problem. |
Thanks for the reviews!
Completely arbitrary. This is more of an interim solution to make sure we have some mechanism to avoid completely eating all available browser storage. The chosen time seems long enough that devs would be able to sniff out any issues. We can certainly tune this as needed or replace this mechanism as our needs change.
No arguments here, we'll iterate on this. I'm also interested to see if it make sense to store subtrees in different keys as well. As our tree grows, I'd be concerned with serialization costs if we continue to use our current method.
Completely reasonable, though it does put additional burden on anyone implementing reducers. Initialization is a very convenient place to change our data handling strategies. |
5e1c700
to
e57ad3f
Compare
window.initialReduxState = serverState; | ||
configStub = sinon.stub( config, 'isEnabled' ); | ||
configStub.withArgs( 'persist-redux' ).returns( false ); | ||
consoleSpy = sinon.spy( console, 'error' ); |
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.
Definitely not necessary to change, though as an FYI, you don't need to assign the spy to a variable. Instead:
sinon.spy( console, 'error' );
expect( console.error.called ).to.equal( false );
console.error.restore();
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.
The bizarre thing was that at my last place we would sometimes see restore() fail 1 out of xx times when using this approach. It was probably due to some leaky test cleanup with a huge test suite, but I've gotten into the habit of storing it in a variable.
Future iterations notwithstanding, I think this is a good first step to address the immediate concern of stale / large data persistence 👍 |
Thanks for the reviews! I'm squishing commits. |
e57ad3f
to
e5d8fc5
Compare
Framework: build redux store from scratch if persisted data is too old
If persisted data for our redux store is too old ( > 7 days ) we build the redux store from scratch. This also adds missing tests for initial-state.js which also covers some initial server state behavior
Testing Instructions
In
development.json
setpersist-redux
to trueIn the console set localStorage debug to 'calypso:state'
Start up Calypso and navigate. The persisted store should load correctly without issues.
Tests in
client/state
passcc @rralian @aduth @mtias @dmsnell @ockham @seear