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

Big risk of loosing data on ClientResetRequiredError #5944

Open
sipersso opened this Issue May 11, 2018 · 10 comments

Comments

Projects
None yet
4 participants
@sipersso
Copy link

sipersso commented May 11, 2018

The documentation says it is my responsibility to close realms finished using them. However, in practice, it turns out it is not so easy. When doing a client reset and a realm instance is open, the app will crash and you will loose any unsynced data, so it is very important to be able to close it. This is super tricky to get right!

The documentation says a good practice is to close the realm when the activity is destroyed. But onDestroy is not always called immediately. This makes it almost impossible to guarantee that all realm instances have been closed.

In my case a realm instance from my main activity remains even after calling finish on that activity and starting another responsible for handling Client Resets. In the end I had to put in a thread sleep in my client reset activity in order to give android time to destroy the previous activity before I could execute the reset. Is this really the way to go?

The swift documentation says the following

It is extremely important that your application listen for client reset errors and, at the very least, make provisions to save user data created or modified after a client reset is triggered so it can later be written back to the re-downloaded copy of the Realm.

In the Android Docs, client resets aren't even mentioned. And as it turns out, they are extremely hard to get right. If there is a recommended way to execute a client reset properly, please provide documentation for it.

Version of Realm and tooling

Realm version(s): 5.1.0

Realm sync feature enabled: yes

Android Studio version: 3.1

Which Android version and device: Android 8.1, Nexus 5X

@cmelchior

This comment has been minimized.

Copy link
Contributor

cmelchior commented May 12, 2018

Hmm, we should have some docs on Client Reset, but I cannot find them either right now. I'll investigate that.

But that said, you are right that handling it is far from straightforward. What you are running into is how the activity lifecycle works, so the next activity onCreate is called before the last onDestroy.

We do have some plans for improving the situation though but don't have a definite timeline to disclose yet.

@cmelchior cmelchior added the T:Doc label May 12, 2018

@Zhuinden

This comment has been minimized.

Copy link
Contributor

Zhuinden commented May 13, 2018

In case of a multi-Activity system, the only way I can imagine is if "possible Realm invalidation" is handled in onStart() and RealmResults are re-initialized.

Force closing UI Thread Realm is possible with a while(!realm.isClosed()) realm.close() but it obviously invalidates all previous activity's realms, and it works only if global instance count == 1 (UI thread only at the time)

I'm honestly just thinking about it now but it does seem tricky

@sipersso

This comment has been minimized.

Copy link

sipersso commented May 13, 2018

@Zhuinden not sure what you mean. I have a root activity (A) with no references to realm that creates the main activity (B) that opens a realm onCreate and closes it onDestroy (via a Android ViewModel from the new architecture components).

When a client reset is detected, activity B is finished. A gets onActivityResult when B is finished and I start activity C that handles client resets. I tried delaying the reset as much as possible, but even if starting the client reset in onPostResume() of activity C, activity B onDestroy() hasn't been called yet. The realm reference from activity B is the only open reference.

What I did to resolve it was to not start the reset immediately, instead I was forced to do something like this (sample written in Kotlin)

private fun executeReset(error:ClientResetRequiredError){
    if(Realm.getGlobalInstanceCount(Realm.getDefaultConfiguration())> 0){
        //Open realms aren't closed yet, wait
        val handler = Handler()
         handler.postDelayed(Runnable {
            executeReset(error)
        }, 500)
       	return
    }
    //Now we can execute reset....
}

Doesn't feel like a very pretty solution, but it was the only way I could get it working.

@cmelchior

This comment has been minimized.

Copy link
Contributor

cmelchior commented May 16, 2018

Hi @sipersso

Yes, this is an unfortunate side-effect of the Android Lifecycle. The recommendation we normally have for opening/closing in onCreate/onDestroy is precisely because it allows you to "move" the Realm instance between activities, but it is also a bit unpredictable which bites us here.

For now, I think your approach is pretty pragmatic, also considering that Client Reset isn't instantaneous. So you are probably forced to have some kind of spinner anyway.

@sipersso

This comment has been minimized.

Copy link

sipersso commented May 16, 2018

@cmelchior thanks! Good to get feedback on that my approach seems ok. Also glad that you seem to take the problems with ClientResets seriously and are looking into the documentation. Correct handling of ClientResets has been a major blocker for me for a long time.

@bmunkholm

This comment has been minimized.

Copy link
Contributor

bmunkholm commented May 16, 2018

@sipersso We will also look into how we can make it much better and easier to handle. We know this is not fun to deal with.

@sipersso

This comment has been minimized.

Copy link

sipersso commented Jan 10, 2019

@bmunkholm Any progress on this issue? I am still having a lot of problems using Realm Cloud and ClientResetErrors. When signing out one user and signing in another, I basically get ClientResetErrors all the time

@bmunkholm

This comment has been minimized.

Copy link
Contributor

bmunkholm commented Jan 10, 2019

@sipersso So to hear that it causes such problems for you.
But it sounds likely something else is wrong if you get ClientResetErrors just signing out/in users.
Could you please detail that much more? If possible it would be fantastic if you can reduce your experience down to a small reproducible and self contained repro case/app so we can look at it?

We have had to prioritize other issues, but are actually now in active progress on a better Client Reset functionality that will be transparent and avoid data loss. I still can't predict it's completion date, but it's being worked on now.

@sipersso

This comment has been minimized.

Copy link

sipersso commented Jan 10, 2019

I think it may be related to that Realm files are still laying around after the user has been signed out.
#6006
https://forums.realm.io/t/synced-realm-is-not-cleared-on-logout/2336

I get the errors when signing in a user that has previously been signed out without restarting the app. I suspect that since the realm files are still there (they will be deleted on next launch) this is what causing the issue. I guess an ugly workaround would be to do a System.exit() to kill the process after logging out, but it wouldn't be a nice experience.

If I kill the app manually after signing out I don't get any errors. That said, since I do get client reset errors, I think I probably still need to handle it in a nice way.

I'll see what I can do about getting a reproducible case.

@sipersso

This comment has been minimized.

Copy link

sipersso commented Jan 11, 2019

It turned out that the problems with client reset was caused by that I was specifying a directory in the sync configuration instead of leaving it to default.

SyncUser.getCurrentUser().createConfiguration("realmUrl").directory(myDirector).addModule(myModule()).build()

When removing the directory in the configuration builder I didn't get ClientResets when switching anymore :)

Still, because of these problems I am very scared about client reset errors. I posted about client resets in June 2017 expressing my concerns about the difficulty to test and verify the error handling on the Realm Platform: https://forum.realm.io/t/how-can-i-test-my-apps-error-handling/393/

ClientResets are not even mentioned in the docs anymore. Should I just ignore this issue and let the client crash on reset?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment