rx-preferences icon indicating copy to clipboard operation
rx-preferences copied to clipboard

apply() is lossy

Open kurtisnelson opened this issue 6 years ago • 7 comments

Using apply() to save preferences is dangerous as it can and will silently fail. Instead, all sets should use commit() and return a completable, throwing an error if commit() returns false.

kurtisnelson avatar Jul 25 '18 23:07 kurtisnelson

Somewhere you dropped an "optionally" from your feature request, right? Almost no one will want to use this as it destroys the ergonomics of the API and few will be using preferences for anything where the absence of durability is a real problem.

Prior art: #110 #42

JakeWharton avatar Jul 25 '18 23:07 JakeWharton

The existing API could at least track the failure somewhere. At scale I've gotten many a bug report where a feature seemed to be not working where in fact a preference was not persisting. It's super handy to at least have the exception in my crash reporting system so I know what happened.

kurtisnelson avatar Jul 25 '18 23:07 kurtisnelson

I think I've got a race condition because of the apply(). My theory is that when another observer subscribes before the data is actually updated within apply() then the observer will get stale data.

p.s. More about the problem: https://stackoverflow.com/questions/49593476/android-sharedpreferences-apply-race-condition Look at the Mark Keen's comment.

sevar83 avatar Aug 20 '18 11:08 sevar83

I'm seeing that the library creates a new Preferences.Editor every time changes are made. Considering that apply() is synchronous and atomic but it's called from different Editor instances, would using the same instance of Editor fix the problem?

kirillzh avatar Mar 18 '19 01:03 kirillzh

We also encountered a major problem because of apply(). We NEED the atomic persistence to disk.

I agree with not destroying the API, but why not expose the possibility from the library? Currently it's not possible to perform commit() using RxSharedPreferences. How about some atomicSet() method?

sirknigget avatar Aug 07 '19 14:08 sirknigget

I ended up writing a library that provides a proper async key-value store: https://github.com/uber/simple-store

kurtisnelson avatar Aug 07 '19 19:08 kurtisnelson

Still missing this basic functionality. The current library completely hides basic Android API stuff that I would normally use, and I end up having to patch around RxSharedPreferences in order to be able to:

  • Call Editor.commit() when setting a preference.
  • Access the SharedPreferences field inside a RealPreference ( current it's: private final SharedPreferences preferences; )

In the current situation I have to either fork rx-preferences and change those library classes, patch around those limitations, or move to using another library.

I think it's a very small, easy to implement request, and it doesn't break anything. Just add "setSync" to RealPreference which would call Editor.commit()...

sirknigget avatar Jun 22 '20 07:06 sirknigget