Skip to content
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

Subscriber breaks with react-native and async storage #2286

Closed
ospfranco opened this issue Jun 16, 2020 · 24 comments
Closed

Subscriber breaks with react-native and async storage #2286

ospfranco opened this issue Jun 16, 2020 · 24 comments

Comments

@ospfranco
Copy link

Case

I was just developing an app using rxdb and react-native, when the time came to update a record on the database, suddenly a subscription on a collection broke

Issue

triggering an update on document (via atomicSet or any other update operation) breaks the query response on other parts of the app

Reproducible example:

I've created a repo with the issue:

https://github.com/ospfranco/rxdb-rn-bug

to reproduce:

  1. clone and run the app: yarn, yarn ios
  2. click on add random node a couple of times, so you have some elements
  3. click on one of the ids on the list
  4. click on randomly update selected node, it will do an atomic update and all of the sudden the list of elements will be cleared, and only the selected node will remain
@pubkey
Copy link
Owner

pubkey commented Jun 16, 2020

Can you disable eventReduce and try if that still occurs?
Also please subscribe to the change-event stream of the database and check if your write appears there.

@ospfranco
Copy link
Author

ospfranco commented Jun 17, 2020

  • I disabled eventReduce, yet the problem still occurs
  • I'm not sure what you mean by the change-event stream, I did this:
node.$.subscribe((changeEvent) =>
            console.warn(`node changed`, changeEvent),
          );

the change gets logged, saving was never a problem

@pubkey
Copy link
Owner

pubkey commented Jun 17, 2020

Have you done a console log here? maybe the change detection is just broken but the data actually gets emitted.

@ospfranco
Copy link
Author

ospfranco commented Jun 17, 2020

I did, but the problem is not the saving of the data... have you seen the code?

there are two calls:

  1. used on the list is a rxjs subscription, using find(). ... .$.subscribe(...)
  2. the second one is a findOne(). ... .exec() call

whenever I write something (1) breaks, and returns the "cached" result of the findOne call

@ospfranco
Copy link
Author

oh sorry, you linked directly to the code, yes, I added a console log, but really... only one item is returned, I did see a funny behavior sometimes though, all the items would be returned a couple of times, but then there would be two more emitted values with only 1 entry

@pubkey
Copy link
Owner

pubkey commented Jun 18, 2020

Hi. Few more stuff to try:

  • Does this also occur with the memory adapter?
  • Does this only occur on iOS or also on Android?

I have no iOS devices. If this is reproducible on android I will start digging deeper with your repo.

@ospfranco
Copy link
Author

  • I cannot test the memory adapter, I tried to use it but it fails with this error:

error: Error: Unable to resolve module assert from node_modules/levelup/lib/levelup.js: assert could not be found within the project.

It seems like it uses some Node.js api, so it is not compatible with react-native

  • Yes, it is also happening on android when using the adapter for AsyncStorage, happens on simulator so you should have no problem reproducing the issue

@pubkey
Copy link
Owner

pubkey commented Jun 19, 2020

I do not get it started
I installed the expo-cli globally

yarn run v1.22.4
$ react-native run-android
info Running jetifier to migrate libraries to AndroidX. You can disable it using "--no-jetifier" flag.
Jetifier found 966 file(s) to forward-jetify. Using 8 workers...
info Starting JS server...
/bin/sh: 1: adb: not found
info Launching emulator...
error Failed to launch emulator. Reason: No emulators found as an output of `emulator -list-avds`.
warn Please launch an emulator manually or connect a device. Otherwise app may fail to launch.
info Installing the app...

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.0.1/userguide/command_line_interface.html#sec:command_line_warnings

FAILURE: Build failed with an exception.

* What went wrong:
Task 'installDebug' not found in project ':app'.

* Try:
Run gradlew tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 2s

error Failed to install the app. Make sure you have the Android development environment set up: https://reactnative.dev/docs/environment-setup. Run CLI with --verbose flag for more details.
Error: Command failed: ./gradlew app:installDebug -PreactNativeDevServerPort=8081

FAILURE: Build failed with an exception.

* What went wrong:
Task 'installDebug' not found in project ':app'.

* Try:
Run gradlew tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 2s

    at makeError (/home/dnl/workspace/rxdb-rn-bug/node_modules/execa/index.js:174:9)
    at /home/dnl/workspace/rxdb-rn-bug/node_modules/execa/index.js:278:16
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async runOnAllDevices (/home/dnl/workspace/rxdb-rn-bug/node_modules/@react-native-community/cli-platform-android/build/commands/runAndroid/runOnAllDevices.js:94:5)
    at async Command.handleAction (/home/dnl/workspace/rxdb-rn-bug/node_modules/@react-native-community/cli/build/index.js:186:9)
error Command failed with exit code 1.


Can I somehow start this without having to install the full android emulator?
I thought expo works with QR code so I can start it on my smartphone.

@ospfranco
Copy link
Author

it's not an expo app, it is pure react native, so I guess not, either download android studio or you can just copy&paste the code in a new expo project, after all it's only like 3 files and the dependencies

@pubkey
Copy link
Owner

pubkey commented Jun 20, 2020

Ok I will try when I find the time.

Can you try enabling pouchdb-debug? Then we could see if this is a RxDB bug or a pouch bug.

import pouchdbDebug from 'pouchdb-debug';
import {
    PouchDB
} from 'rxdb';
PouchDB.plugin(pouchdbDebug);
// PouchDB.debug.enable('*');

Also I have seen you are using a null-check here are you sure the db variable is never null at that point?

@ospfranco
Copy link
Author

ospfranco commented Jun 21, 2020

@pubkey I have updated the original repo to expo, hopefully that will save you some time.

I copied&pasted the code for debug, nothing out of the ordinary is logged:

WARNING
15:43
node changed, Object {
  "_rev": "2-62755508d77e48db904665a18f72bc32",
  "authorId": "HARDCODED AUTHOR",
  "createdAt": 1592746710509,
  "id": "bcfa09db-315a-4a58-93ac-861c2ea729cc",
  "text": "0.624582943994004",
  "type": "text",
  "updatedAt": 1592746710513,
}

Stack trace:
  node_modules/react-native/Libraries/YellowBox/YellowBox.js:71:8 in console.warn
  node_modules/expo/build/environment/muteWarnings.fx.js:18:23 in warn
  App.js:56:27 in node.$.subscribe$argument_0
  node_modules/rxjs/internal/Subscriber.js:204:12 in SafeSubscriber.prototype.__tryOrUnsub
  node_modules/rxjs/internal/Subscriber.js:142:17 in SafeSubscriber.prototype.next
  node_modules/rxjs/internal/Subscriber.js:88:25 in <anonymous>
  node_modules/rxjs/internal/Subscriber.js:65:18 in prototype.next
  node_modules/rxjs/internal/BehaviorSubject.js:34:24 in prototype._subscribe
  node_modules/rxjs/internal/Observable.js:43:12 in prototype._trySubscribe
  node_modules/rxjs/internal/Observable.js:27:13 in prototype.subscribe
  node_modules/rxjs/internal/Observable.js:27:13 in prototype.subscribe
  App.js:54:26 in <anonymous>
  node_modules/promise/setimmediate/core.js:37:14 in tryCallOne
  node_modules/promise/setimmediate/core.js:123:25 in setImmediate$argument_0
  node_modules/react-native/Libraries/Core/Timers/JSTimers.js:146:14 in _callTimer
  node_modules/react-native/Libraries/Core/Timers/JSTimers.js:194:17 in _callImmediatesPass
  node_modules/react-native/Libraries/Core/Timers/JSTimers.js:458:30 in callImmediates
  [native code]:null in callImmediates
  node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:407:6 in __callImmediates
  node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:143:6 in __guard$argument_0
  node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:384:10 in __guard
  node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:142:17 in __guard$argument_0
  [native code]:null in flushedQueue
  [native code]:null in callFunctionReturnFlushedQueue
  ...
WARNING
15:43
node changed, Object {
  "_rev": "3-7ba98b066a4044a68da831f88b0b9d95",
  "authorId": "HARDCODED AUTHOR",
  "createdAt": 1592746710509,
  "id": "bcfa09db-315a-4a58-93ac-861c2ea729cc",
  "text": "0.6055807884750679",
  "type": "text",
  "updatedAt": 1592746710513,
}

Stack trace:
  node_modules/react-native/Libraries/YellowBox/YellowBox.js:71:8 in console.warn
  node_modules/expo/build/environment/muteWarnings.fx.js:18:23 in warn
  App.js:56:27 in node.$.subscribe$argument_0
  node_modules/rxjs/internal/Subscriber.js:204:12 in SafeSubscriber.prototype.__tryOrUnsub
  node_modules/rxjs/internal/Subscriber.js:142:17 in SafeSubscriber.prototype.next
  node_modules/rxjs/internal/Subscriber.js:88:25 in <anonymous>
  node_modules/rxjs/internal/Subscriber.js:65:18 in prototype.next
  node_modules/rxjs/internal/Subject.js:59:12 in prototype.next
  node_modules/rxjs/internal/BehaviorSubject.js:50:30 in <anonymous>
  http://127.0.0.1:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:130874:31 in _handleChangeEvent
  [native code]:null in _handleChangeEvent
  http://127.0.0.1:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:153496:40 in <unknown>
  node_modules/rxjs/internal/Subscriber.js:204:12 in SafeSubscriber.prototype.__tryOrUnsub
  node_modules/rxjs/internal/Subscriber.js:142:17 in SafeSubscriber.prototype.next
  node_modules/rxjs/internal/Subscriber.js:88:25 in <anonymous>
  node_modules/rxjs/internal/Subscriber.js:65:18 in prototype.next
  node_modules/rxjs/internal/operators/filter.js:51:20 in FilterSubscriber.prototype._next
  node_modules/rxjs/internal/Subscriber.js:65:18 in prototype.next
  node_modules/rxjs/internal/operators/filter.js:51:20 in FilterSubscriber.prototype._next
  node_modules/rxjs/internal/Subscriber.js:65:18 in prototype.next
  node_modules/rxjs/internal/operators/filter.js:51:20 in FilterSubscriber.prototype._next
  node_modules/rxjs/internal/Subscriber.js:65:18 in prototype.next
  node_modules/rxjs/internal/Subject.js:59:12 in prototype.next
  node_modules/rxdb/dist/lib/rx-database.js:127:22 in $emit
  [native code]:null in $emit
  http://127.0.0.1:19001/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&minify=false&hot=false:131078:21 in <unknown>
  node_modules/promise/setimmediate/core.js:37:14 in tryCallOne
  node_modules/promise/setimmediate/core.js:123:25 in setImmediate$argument_0
  node_modules/react-native/Libraries/Core/Timers/JSTimers.js:146:14 in _callTimer
  node_modules/react-native/Libraries/Core/Timers/JSTimers.js:194:17 in _callImmediatesPass
  node_modules/react-native/Libraries/Core/Timers/JSTimers.js:458:30 in callImmediates
  [native code]:null in callImmediates
  node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:407:6 in __callImmediates
  node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:143:6 in __guard$argument_0
  node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:384:10 in __guard
  node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:142:17 in __guard$argument_0
  [native code]:null in flushedQueue
  [native code]:null in invokeCallbackAndReturnFlushedQueue
  ...

But you can try it yourself more easily now I hope

@pubkey
Copy link
Owner

pubkey commented Jun 21, 2020

Thank you, I started it and I can reproduce the problem now.

@pubkey
Copy link
Owner

pubkey commented Jun 21, 2020

It works correctly when I remove the sorting

db.nodes
  .find()
  // .sort({createdAt: 'desc'})
  .$.subscribe((dbNodes) => {
    console.warn('query$ emitted new result with ' + dbNodes.length + ' docs');
    if (dbNodes) {
      setNodes(dbNodes);
    }
  });

@pubkey
Copy link
Owner

pubkey commented Jun 21, 2020

I added some logging to the rxdb/dist/lib in the node_modules.
I think RxDB is sending the correct query to pouchdb but there is gets the wrong results.
It indicates this is a pouchdb/asyncstorage bug, we should be able to reproduce this with plain pouchdb and no RxDB.

@pubkey
Copy link
Owner

pubkey commented Jun 21, 2020

Ok so directly checking a plain pouchdb query after the update will also return the wrong results

  async function randomlyUpdate() {
    if (selectedNode) {
      await selectedNode.atomicSet('text', `${Math.random()}`);
    }

    const plainPouchResults = await db.nodes.pouch.find({
      selector: {
        createdAt: {
          $gt: 0
        }
      },
      sort: ['createdAt']
    });
    console.warn('plainPouchResults: ' + JSON.stringify(plainPouchResults));
  }

@ospfranco
Copy link
Author

yeah, I believe it is an adapter bug, somehow the wrong answer is being cached

@ospfranco
Copy link
Author

hi @pubkey, is there any way I can support you with this?

@pubkey
Copy link
Owner

pubkey commented Jun 25, 2020

I think this is a pouchdb/asyncstorage bug.
I am not working on this atm

@ospfranco
Copy link
Author

well, yeah, it is a asyncstorage bug, but... it is a major issue, react-native just does not work, rxdb cannot be used on production if the data cannot be updated, don't want to put to much pressure on this, but if there will be no plans to fix it, you might as well just remove it from the list of supported platforms

@ospfranco
Copy link
Author

Just FYI, I got the sqlite2 adapter working by simply modifying the podspec, the bug is not present there, I would suggest removing the old adapter documentation since it is abandoned anyways, I submitted a PR that includes macOS support:

craftzdog/react-native-sqlite-2#82

pubkey added a commit that referenced this issue Jul 13, 2020
@pubkey
Copy link
Owner

pubkey commented Jul 13, 2020

I added a warning to the docs. Thank you for your investigation.

@pubkey pubkey closed this as completed Jul 13, 2020
@alex-hladun
Copy link
Contributor

Hi @ospfranco, when you got this working with the sqlite2 adapter, were you using expo or bare react-native? Expo has its own version of sqlite and I am trying to integrate it without success.

@ghost
Copy link

ghost commented Jan 29, 2022

Just wanted to add that I am also unable to use the sqlite adapter with expo. Would be nice if there was an example in the docs demonstrating the use of expo-sqlite instead of react-native-sqlite-2.

@pubkey
Copy link
Owner

pubkey commented Jan 29, 2022

@infosisio make a PR

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

No branches or pull requests

3 participants