realm / realm-js

Realm is a mobile database: an alternative to SQLite & key-value stores
https://realm.io
Apache License 2.0
5.62k stars 558 forks source link

Problems with Deleting Record with Realm for React Native #4948

Closed s1tony closed 1 year ago

s1tony commented 1 year ago

When I attempt to delete a record, my app instantly crashes and I cannot seem to catch the exception. From the MongoDB support team, it seems the context is being closed too soon. Any idea what is happening? This happens whether I use a listener or not.

image

Delete method:

  const deleteList = (listId: string): void => {
    const listRealm = realmRef.current;
    const list = listRealm?.objectForPrimaryKey<List>("List", new ObjectId(listId));
    try {
      listRealm?.write<void>(() => {
        if (list) {
          listRealm?.delete(list);
        }
      })
    } catch(error) {
      console.log(error);
    }
  };

React Native 0.70

SDK: android vRealmJS/10.21.1 Platform Version: 31

MongoDB version 5.0.12

ianpward commented 1 year ago

Hi can you please provide the Device Sync AppId so we can take a look on the backend logs? Thank you

s1tony commented 1 year ago

Hi Ian,

listmaker-luqgq

Also, I am utilizing Flexible Sync.

Thank you so much,

Tony

ianpward commented 1 year ago

@s1tony looks like your access token is expired and you're not refreshing it. Not sure why but try re-authenticating

ianpward commented 1 year ago

You should be able to see this in the client-side logs if you have the logger enabled I believe?

s1tony commented 1 year ago

I need to enable the logger, I believe. I am not understanding why I can do everything but delete and not be authenticated? Perhap I am misunderstanding?

On Mon, Sep 26, 2022 at 11:26 AM Ian Ward @.***> wrote:

You should be able to see this in the client-side logs if you have the logger enabled I believe?

— Reply to this email directly, view it on GitHub https://github.com/realm/realm-js/issues/4948#issuecomment-1258307189, or unsubscribe https://github.com/notifications/unsubscribe-auth/AP57MNK57GNDNZTH7TLWRVDWAHFD7ANCNFSM6AAAAAAQUZLDZY . You are receiving this because you were mentioned.Message ID: @.***>

ianpward commented 1 year ago

you should see it here - https://www.mongodb.com/docs/realm-sdks/js/latest/Realm.App.Sync.html#~LogLevel

s1tony commented 1 year ago

Thanks - will try this afternoon

s1tony commented 1 year ago

I setup logging and it logs fine until I try the delete and then the app crashes and no more logging :(.

s1tony commented 1 year ago

Just before the app crashes: image

s1tony commented 1 year ago

Is this the culprit:

"Order Matters

In collection notification handlers, always apply changes in the following order: deletions, insertions, then modifications. Handling insertions before deletions may result in unexpected behavior."

s1tony commented 1 year ago

I just explored the above by removing the listener before the delete and the issue still occurs.

This is the exception from the MongoDB logs:

integrating changesets failed: retryable error while committing integrated changesets: failed to apply changesets: failed to insert into history: connection(listcluster-shard-00-02.mewf8.mesh.mongodb.net:30558[-41158]) incomplete read of message header: context canceled (ProtocolErrorCode=201)

kraenhansen commented 1 year ago

@s1tony are you registering any listeners on List collection or any objects containing the object you're deleting?

If so, can you catch any errors if you try-catch in those listener callback functions? You might be hitting https://github.com/realm/realm-js/issues/2654

s1tony commented 1 year ago

Yes, I did have listeners on the List collection. In fact, I was just doing some testing of adding and deleting from the List collection without the listeners and things seem to be working. As I recall, I could not catch any exceptions in the listener callback functions, but can try again.

Thanks for the feedback.

s1tony commented 1 year ago

Hmmm, the App crashed, as it did before, and I was not able to catch with a try-catch.

I reckon I will have to rewrite the code without the use is a listener 👎

s1tony commented 1 year ago

OK, so more test results. Listener or not, the issue arises when I add a List and then delete the List. No exception, no logs, just App crash:

Logs:

integrating changesets failed: retryable error while committing integrated changesets: error getting latest server version: connection(listcluster-shard-00-02.mewf8.mesh.mongodb.net:30558[-76754]) incomplete read of message header: context canceled (ProtocolErrorCode=201)

s1tony commented 1 year ago

I added react-native-exception-handler and still cannot catch the exception - the App just quits. I am out of ideas at this point and would really appreciate any ideas, thoughts or recommendations.

kraenhansen commented 1 year ago

What host machine are you developing on? I'm asking to determine what NDK might be used when compiling the app, specifically if you're on an Apple M1 / aarch64 and hitting this branch of the RN template: https://github.com/facebook/react-native/blob/v0.70.0/template/android/build.gradle#L12

Could I get you to share the output of running from the root of your repository?

npx react-native info
s1tony commented 1 year ago

info Fetching system and libraries information... System: OS: Windows 10 10.0.19044 CPU: (16) x64 11th Gen Intel(R) Core(TM) i7-11700K @ 3.60GHz Memory: 18.01 GB / 31.83 GB Binaries: Node: 14.18.0 - C:\Program Files\nodejs\node.EXE Yarn: Not Found npm: 8.9.0 - C:\Program Files\nodejs\npm.CMD Watchman: Not Found SDKs: Android SDK: Not Found Windows SDK: Not Found IDEs: Android Studio: AI-212.5712.43.2112.8609683 Visual Studio: Not Found Languages: Java: javac 17 - C:\Program Files\Common Files\Oracle\Java\javapath\javac.EXE npmPackages: @react-native-community/cli: Not Found react: 18.1.0 => 18.1.0 react-native: 0.70.1 => 0.70.1 react-native-windows: Not Found npmGlobalPackages: react-native: Not Found

s1tony commented 1 year ago

I am willing to build and test the library locally, if there is any way I can debug while it is running, in order to catch this "uncatchable error". I would just need some help and instructions on how to do so. I use VS for work, so I can install it on my home machine and utilize the C++ code.

On Sun, Oct 2, 2022 at 3:27 PM Kræn Hansen @.***> wrote:

What host machine are you developing on? I'm asking to determine what NDK might be used when compiling the app, specifically if you're on an Apple M1 / aarch64 and hitting this branch of the RN template: https://github.com/facebook/react-native/blob/v0.70.0/template/android/build.gradle#L12

Could I get you to share the output of running from the root of your repository?

npx react-native info

— Reply to this email directly, view it on GitHub https://github.com/realm/realm-js/issues/4948#issuecomment-1264726451, or unsubscribe https://github.com/notifications/unsubscribe-auth/AP57MNO755GAVRJR4RUYZZTWBHV2JANCNFSM6AAAAAAQUZLDZY . You are receiving this because you were mentioned.Message ID: @.***>

kneth commented 1 year ago

@s1tony We need to investigate a bit more. Out of curiosity, which Android version do you target?

s1tony commented 1 year ago

I think 31 - but will verify and let you know.

On Tue, Oct 4, 2022 at 7:34 AM Kenneth Geisshirt @.***> wrote:

@s1tony https://github.com/s1tony We need to investigate a bit more. Out of curiosity, which Android version do you target?

— Reply to this email directly, view it on GitHub https://github.com/realm/realm-js/issues/4948#issuecomment-1266926259, or unsubscribe https://github.com/notifications/unsubscribe-auth/AP57MNMDOUHB73MH2OIOZN3WBQP6TANCNFSM6AAAAAAQUZLDZY . You are receiving this because you were mentioned.Message ID: @.***>

s1tony commented 1 year ago

Pretty sure 31

On Tue, Oct 4, 2022, 7:37 AM Tony Schilling @.***> wrote:

I think 31 - but will verify and let you know.

On Tue, Oct 4, 2022 at 7:34 AM Kenneth Geisshirt @.***> wrote:

@s1tony https://github.com/s1tony We need to investigate a bit more. Out of curiosity, which Android version do you target?

— Reply to this email directly, view it on GitHub https://github.com/realm/realm-js/issues/4948#issuecomment-1266926259, or unsubscribe https://github.com/notifications/unsubscribe-auth/AP57MNMDOUHB73MH2OIOZN3WBQP6TANCNFSM6AAAAAAQUZLDZY . You are receiving this because you were mentioned.Message ID: @.***>

kneth commented 1 year ago

@s1tony We are currently investigating the ticket, and I hope that I will be able to come with an update early next week.

s1tony commented 1 year ago

Hi guys, I think I have made some headway. After thinking about this some more and reviewing my code, it sure seems to have something to do with listeners. After a list is added, the app routes to a details page, which display the list items - and instantiates two listeners. One is on List and the other on ListItems, which is an embedded type within List.

A quick test seemed to confirm this as the cause. I will do some more testing and see if I can find another way to implement this page. Since users can share lists, I wanted the List Items to be updated if another user made a change.

s1tony commented 1 year ago

Unfortunately, it seems if I have a listener on the List or ListItems object at any time - even if I remove the listener before the delete - and try to delete - the app will crash.

Doesn't this pretty much deem listeners useless for me? This is very frustrating and very much limits what I can do.

kraenhansen commented 1 year ago

@s1tony can you share the code for the callback you're adding as a listener on these collections? And did you try my suggestion of adding a try-catch block around the entire body of those listener callbacks?

If you for example add this callback:

items.addListener(() => {
  // Some of your code, which might throw
});

it would turn into

items.addListener(() => {
  try {
    // Some of your code, which might throw
  } catch (err) {
    console.error(err);
  }
});
s1tony commented 1 year ago

Hi, I thought I had taken your suggestion at one time, but am losing track now. However, today I was going down the road of trying to remove the listener(s) before doing the delete, which was having inconsistent results.

I just tried your suggestion within my attempt to remove the listener upon the page losing focus. Anyway, here is a snippet of my now messy code:

` useFocusEffect( useCallback(() => { const item = listData.getList(listId); setList(item); //item?.listItems.addListener(listItemUpdateListener);

  item?.listItems.addListener((listItems) => {
    try {
      setListItems(getListItems(listItems));  
    } catch (err) {
      console.error(err);
    }
  });

  console.log('Add event listener');
  //item?.addListener(listUpdateListener);

  return () => {
    console.log('Remove event listener');
    //item?.listItems.removeListener(listItemUpdateListener);

    item?.listItems.removeListener((listItems) => {
      try {
        setListItems(getListItems(listItems));  
      } catch (err) {
        console.error(err);
      }
    });

    //item?.removeListener(listUpdateListener);
  };
}, [])

); `

Here is what I received:

image

This makes sense, I guess - except I thought removing the listener would take care of this.

I reckon my journey continues.

s1tony commented 1 year ago

I think what I tried originally after your suggestion was to put the try/catch in the callback method:

`  const listsUpdateListener = (lists: Realm.Collection<List & Realm.Object>) => {
    try {
      const items: IBaseList[] = [];

      lists?.forEach(t => {
        items.push({ _id: t._id, date: t.date, name: `${t.name}`, userId: t.userId, ownsList: t.userId === currentUser?.id});   
      });

      setLists(items);
    } catch(ex) {
      console.error(ex);
    }
  };
`

and then

listRawData?.removeListener(listsUpdateListener);

s1tony commented 1 year ago

It sure seems as though it was the listener on my details page, not the list page, and so my attempts to catch the exception were not successful because I was trying to catch on the list page.

With the try/catch on the details page, I can catch the exception and continue.

I feel as though I went round and round, getting lost trying different things - and for this I apologize.

danieltabacaru commented 1 year ago

@s1tony do you have a stack trace and/or full client logs?

s1tony commented 1 year ago

Yes, I will get what I can for you, as I can cause this exception to happen at will.

On Mon, Oct 10, 2022 at 9:32 AM Daniel Tabacaru @.***> wrote:

@s1tony https://github.com/s1tony do you have a stack trace and/or full client logs?

— Reply to this email directly, view it on GitHub https://github.com/realm/realm-js/issues/4948#issuecomment-1273408301, or unsubscribe https://github.com/notifications/unsubscribe-auth/AP57MNNESIXILFGWDQCQUTDWCQSF7ANCNFSM6AAAAAAQUZLDZY . You are receiving this because you were mentioned.Message ID: @.***>

s1tony commented 1 year ago

I don't have a full stack trace, but let me see what I can do.

From the logs:

image

s1tony commented 1 year ago

Yes, the exception is the following:

[Error: Access to invalidated Collection object]

What is happening is I have a listener on the embedded ListItems array within List in a detailed page. When I add a List, the application goes to this page where details (List Items) can be added. Then when I go to the Lists page and try to delete this List, the exception occurs.

While this makes sense, what is frustrating is I tried to remove the listener when leaving the page, but the exception still occurs.

s1tony commented 1 year ago

I think we have everything straightened out, for the most part. It seems that even if a listener is removed, it may not be completely removed. The code updates I made to handle this are as follows:

`  const listItemUpdateListener = (listItems: Realm.Collection<ListItem>) => {
    try {
      if (listItems.isValid()) {
        setListItems(getListItems(listItems));  
      }
    } catch(err) {
      console.error(err);
    }
  };
`