You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Huge blocking time as soon as persistQueryClient/createWebStoragePersistor clears the old entries from cache #3034
Describe the bug
If using persistQueryClient and createWebStoragePersistor with window.sessionStorage like in the example below, then the Performance of the Web-App drastically decreases as soon as the sessionStorage is full. In my example each query result can vary from very few data (few numeric values) to very huge amount of data (arrays with length ca. 10000 of objects with ca. 10 keys). Therefore deleting one item from the cache often means that a big item can still not fit into it, resulting in many failed write requests in the current implementation which furthermore results in very huge blocking times of the main thread.
Can you create a codesandbox example with that amount of data please? The auto removal feature is rather new so it could be that its not efficient enough. On the other hand, I’m not sure what we can do apart from removing the oldest query and then try to persist again 🤔
maybe we can also agree that always doing what we are trying to do (remove the oldest item and try to persist again) is not really applicable for all situations. Maybe we could let the user provide an overflowStrategy, which could be either firstInFirstOut (what we have currently), or something else that works better? Maybe even a custom function where the user can return true to keep persisting the query and false to throw it away?
we use try-serialize-catch to detect the maximum space to store now.
It's a performance-sensitive way,
It will cost lots of resources when frequently called with continually increasing queries.
@tilman can try to increase the throttle time, or add dehydrateOptions.shouldDehydrateQuery to filter the persistQueries.
@TkDodo it's a good solution that users can provide a function handling this situation.
But it's hard to define the API. overflowStrategy?: (query: persistedClient ) => persistedClient|false ?
or saveStrategy?: (query: persistedClient ,storage:Storage,retryTimes) => boolean ?
I was working with tilman together on this and we eventually settled on using this custom Storage implementation.
It's basically the same as the default storage from react-query, just way more aggressive when purging data
we didn't notice any performance issues after using this.
I think being able to provide an overflowStrategy or similar would be nice, since our solution requires quite a bit of boilerplate code.
now that the plugin will become stable in v4, I think it's time to decide what we want to do here. The current approach seems to "work", but it's also computationally expensive. Also, we've only added it to the webStoragePersister, but not the AyncStorage one. But in react-native, there is also a limit on how much you can store, and it would be good to also support different overflowStrategies there.
So if someone wants to contribute this to v4 (currently alpha branch), I'd be happy to see your proposals :)
callback function where everyone can react however they want to any kinds of errors while persisting, including overflow errors. We would expect to get a new persistedClient back that might have fewer entries with which we would re-try the save.
additionally, we could export some default strategies to handle these errors that conform to this interface. One would be the current try-remove-old-things handler, but given it has perf issues, I wouldn't use this one per default anymore. We can think about providing more errr handling strategy functions (should be treeshakable if unused), and they should work for both the async persister and the webstorage persister.
not doing LRU anymore per default is breaking, but all of this should be for v4 anyways, and the fix would be simply to import and use the error handler.
I do have a draft PR of the aforementioned proposal, but I would really like some feedback and someone else to take this over. It's missing tests and docs, especially to see if this also works for the async persister:
Activity
TkDodo commentedon Nov 29, 2021
Can you create a codesandbox example with that amount of data please? The auto removal feature is rather new so it could be that its not efficient enough. On the other hand, I’m not sure what we can do apart from removing the oldest query and then try to persist again 🤔
@NewFuture FYI, maybe you’d have an idea here?
TkDodo commentedon Nov 29, 2021
maybe we can also agree that always doing what we are trying to do (remove the oldest item and try to persist again) is not really applicable for all situations. Maybe we could let the user provide an
overflowStrategy, which could be eitherfirstInFirstOut(what we have currently), or something else that works better? Maybe even a custom function where the user can returntrueto keep persisting the query andfalseto throw it away?what do you think?
NewFuture commentedon Nov 30, 2021
we use
try-serialize-catchto detect the maximum space to store now.It's a performance-sensitive way,
It will cost lots of resources when frequently called with continually increasing queries.
@tilman can try to increase the
throttle time, or adddehydrateOptions.shouldDehydrateQueryto filter the persistQueries.@TkDodo it's a good solution that users can provide a function handling this situation.
But it's hard to define the API.
overflowStrategy?: (query: persistedClient ) => persistedClient|false?or
saveStrategy?: (query: persistedClient ,storage:Storage,retryTimes) => boolean?chronark commentedon Feb 8, 2022
I was working with tilman together on this and we eventually settled on using this custom
Storageimplementation.It's basically the same as the default storage from react-query, just way more aggressive when purging data
And then calling it
we didn't notice any performance issues after using this.
I think being able to provide an
overflowStrategyor similar would be nice, since our solution requires quite a bit of boilerplate code.TkDodo commentedon Mar 24, 2022
now that the plugin will become stable in v4, I think it's time to decide what we want to do here. The current approach seems to "work", but it's also computationally expensive. Also, we've only added it to the
webStoragePersister, but not theAyncStorageone. But in react-native, there is also a limit on how much you can store, and it would be good to also support differentoverflowStrategiesthere.So if someone wants to contribute this to v4 (currently
alphabranch), I'd be happy to see your proposals :)TkDodo commentedon Apr 24, 2022
Another idea: instead of providing
overflowStrategy, we could simply provide anhandlePersistError(persistedClient: PersistedClient, error: Error, errorCount: number): Promisable<PersistedClient>callback function where everyone can react however they want to any kinds of errors while persisting, including overflow errors. We would expect to get a new
persistedClientback that might have fewer entries with which we would re-try the save.additionally, we could export some default strategies to handle these errors that conform to this interface. One would be the current try-remove-old-things handler, but given it has perf issues, I wouldn't use this one per default anymore. We can think about providing more errr handling strategy functions (should be treeshakable if unused), and they should work for both the async persister and the webstorage persister.
not doing LRU anymore per default is breaking, but all of this should be for v4 anyways, and the fix would be simply to import and use the error handler.
thoughts?
TkDodo commentedon Apr 24, 2022
I do have a draft PR of the aforementioned proposal, but I would really like some feedback and someone else to take this over. It's missing tests and docs, especially to see if this also works for the async persister:
#3556