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

Realm with sync enabled CRASHES the whole app when "path" is specified #4659

Closed
rogerkerse opened this issue Jun 20, 2022 · 25 comments
Closed
Assignees
Labels
More-information-needed More information is needed to progress. The issue will close automatically in 2 weeks. O-Community T-Bug

Comments

@rogerkerse
Copy link

rogerkerse commented Jun 20, 2022

How frequently does the bug occur?

All the time

Description

I created a demo project that crashes after login immediatelly when in realm configuration we add path variable. It seems like unintended behaviour. When removing path no crash appears.

https://github.com/boltss/realm-sync-demo demo project. That crashes when path is specified.

In our case having 2 realms side by side is mandatory. And to separate them we need to specify path to one.

Stacktrace & log output

ERROR  [Error: Unable to open realm: Incompatible histories. Expected an empty or synced Realm, but found history type 2, top ref 344 Path: /Users/username/Library/Developer/CoreSimulator/Devices/A1DFCA63-1C6D-4666-AA79-024DB7533A92/data/Containers/Data/Application/67EA29FA-8BC7-470C-8B4D-950175BF4B50/Documents/sync.realm
Exception backtrace:
0   RealmSyncDemo                       0x00000001032b655c _ZN5realm21IncompatibleHistoriesC1ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_ + 84
1   RealmSyncDemo                       0x00000001032b54f4 _ZN5realm2DB4openERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEbNS_9DBOptionsE + 6728
2   RealmSyncDemo                       0x00000001032b704c _ZN5realm2DB4openERNS_11ReplicationERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS_9DBOptionsE + 124
3   RealmSyncDemo                       0x00000001032bd868 _ZN5realm2DB6createENSt3__110unique_ptrINS_11ReplicationENS1_14default_deleteIS3_EEEERKNS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_9DBOptionsE + 156
4   RealmSyncDemo                       0x00000001030bc618 _ZN5realm5_impl16RealmCoordinator7open_dbEv + 1212
5   RealmSyncDemo                       0x00000001030bbe9c _ZN5realm5_impl16RealmCoordinator19create_sync_sessionEv + 36
6   RealmSyncDemo                       0x00000001030be614 _ZN5realm5_impl16RealmCoordinator22get_synchronized_realmENS_11RealmConfigE + 80
7   RealmSyncDemo                       0x000000010311a094 _ZN5realm5Realm22get_synchronized_realmENS_11RealmConfigE + 108
8   RealmSyncDemo                       0x00000001030266ec _ZN5realm2js10RealmClassINS_3jsc5TypesEE16async_open_realmEPK15OpaqueJSContextP13OpaqueJSValueRNS0_9ArgumentsIS3_EERNS0_11ReturnValueIS3_EE + 772
9   RealmSyncDemo                       0x000000010301be00 _ZN5realm2js4wrapIXadL_ZNS0_10RealmClassINS_3jsc5TypesEE16async_open_realmEPK15OpaqueJSContextP13OpaqueJSValueRNS0_9ArgumentsIS4_EERNS0_11ReturnValueIS4_EEEEEEPKS9_S8_SA_SA_mPKSI_PSI_ + 56
10  JavaScriptCore                      0x000000019190e9c4 _ZN3JSCL22callJSCallbackFunctionEPNS_14JSGlobalObjectEPNS_9CallFrameE + 524
11  ???                                 0x0000000134205664 0x0 + 5169501796
12  JavaScriptCore                      0x0000000191882320 llint_entry + 151568
13  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
14  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
15  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
16  JavaScriptCore                      0x0000000191883038 llint_entry + 154920
17  JavaScriptCore                      0x0000000191882320 llint_entry + 151568
18  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
19  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
20  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
21  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
22  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
23  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
24  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
25  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
26  JavaScriptCore                      0x0000000191882fa0 llint_entry + 154768
27  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
28  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
29  JavaScriptCore                      0x0000000191882320 llint_entry + 151568
30  JavaScriptCore                      0x0000000191882320 llint_entry + 151568
31  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
32  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
33  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
34  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
35  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
36  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
37  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
38  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
39  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
40  JavaScriptCore                      0x0000000191882320 llint_entry + 151568
41  JavaScriptCore                      0x0000000191882320 llint_entry + 151568
42  JavaScriptCore                      0x00000001918835ec llint_entry + 156380
43  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
44  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
45  JavaScriptCore                      0x00000001918835ec llint_entry + 156380
46  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
47  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
48  JavaScriptCore                      0x0000000191882288 llint_entry + 151416
49  JavaScriptCore                      0x000000019185d064 vmEntryToJavaScript + 264
50  JavaScriptCore                      0x0000000192000e98 _ZN3JSC11Interpreter11executeCallEPNS_14JSGlobalObjectEPNS_8JSObjectERKNS_8CallDataENS_7JSValueERKNS_7ArgListE + 640
51  JavaScriptCore                      0x0000000192329110 _ZN3JSC27boundThisNoArgsFunctionCallEPNS_14JSGlobalObjectEPNS_9CallFrameE + 744
52  JavaScriptCore                      0x000000019185d210 vmEntryToNative + 280
53  JavaScriptCore                      0x0000000192000ec0 _ZN3JSC11Interpreter11executeCallEPNS_14JSGlobalObjectEPNS_8JSObjectERKNS_8CallDataENS_7JSValueERKNS_7ArgListE + 680
54  JavaScriptCore                      0x0000000191927b0c JSObjectCallAsFunction + 760
55  RealmSyncDemo                       0x0000000102eb14b4 _ZN8facebook3jsc10JSCRuntime4callERKNS_3jsi8FunctionERKNS2_5ValueEPS7_m + 268
56  RealmSyncDemo                       0x0000000102ec0820 _ZNK8facebook3jsi8Function4callERNS0_7RuntimeEPKNS0_5ValueEm + 100
57  RealmSyncDemo                       0x0000000102ec075c _ZNK8facebook3jsi8Function4callERNS0_7RuntimeESt16initializer_listINS0_5ValueEE + 112
58  RealmSyncDemo                       0x0000000102ee2800 _ZNK8facebook3jsi8Function4callIJRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEESB_NS0_5ValueEEEESC_RNS0_7RuntimeEDpOT_ + 284
59  RealmSyncDemo                       0x0000000102ee2674 _ZZN8facebook5react11JSIExecutor12callFunctionERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RKN5folly7dynamicEENK3$_5clEv + 140
60  RealmSyncDemo                       0x0000000102ee25c8 _ZNSt3__1L8__invokeIRZN8facebook5react11JSIExecutor12callFunctionERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEESB_RKN5folly7dynamicEE3$_5JEEEDTclscT_fp_spscT0_fp0_EEOSI_DpOSJ_ + 24
61  RealmSyncDemo                       0x0000000102ee2580 _ZNSt3__128__invoke_void_return_wrapperIvLb1EE6__callIJRZN8facebook5react11JSIExecutor12callFunctionERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEESD_RKN5folly7dynamicEE3$_5EEEvDpOT_ + 28
62  RealmSyncDemo                       0x0000000102ee2558 _ZNSt3__110__function12__alloc_funcIZN8facebook5react11JSIExecutor12callFunctionERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEESC_RKN5folly7dynamicEE3$_5NS8_ISH_EEFvvEEclEv + 28
63  RealmSyncDemo                       0x0000000102ee12f8 _ZNSt3__110__function6__funcIZN8facebook5react11JSIExecutor12callFunctionERKNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEESC_RKN5folly7dynamicEE3$_5NS8_ISH_EEFvvEEclEv + 28
64  RealmSyncDemo                       0x0000000102f217e8 _ZNKSt3__110__function12__value_funcIFvvEEclEv + 60
65  RealmSyncDemo                       0x0000000102f216f8 _ZNKSt3__18functionIFvvEEclEv + 24
66  RealmSyncDemo                       0x0000000102c53620 _ZN8facebook5react11JSIExecutor21defaultTimeoutInvokerERKNSt3__18functionIFvvEEENS3_IFNS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEvEEE + 24
67  RealmSyncDemo                       0x0000000102c56584 _ZNSt3__1L8__invokeIRPFvRKNS_8functionIFvvEEENS1_IFNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEvEEEEJS5_SD_EEEDTclscT_fp_spscT0_fp0_EEOSH_DpOSI_ + 92
68  RealmSyncDemo                       0x0000000102c564f8 _ZNSt3__128__invoke_void_return_wrapperIvLb1EE6__callIJRPFvRKNS_8functionIFvvEEENS3_IFNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEvEEEES7_SF_EEEvDpOT_ + 72
69  RealmSyncDemo                       0x0000000102c5647c _ZNSt3__110__function12__alloc_funcIPFvRKNS_8functionIFvvEEENS2_IFNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEvEEEENSA_ISG_EESF_EclES6_OSE_ + 72
70  RealmSyncDemo                       0x0000000102c54ea0 _ZNSt3__110__function6__funcIPFvRKNS_8functionIFvvEEENS2_IFNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEvEEEENSA_ISG_EESF_EclES6_OSE_ + 72
71  RealmSyncDemo                       0x0000000102ee0854 _ZNKSt3__110__function12__value_funcIFvRKNS_8functionIFvvEEENS2_IFNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEvEEEEEclES6_OSE_ + 104
72  RealmSyncDemo                       0x0000000102ed0800 _ZNKSt3__18functionIFvRKNS0_IFvvEEENS0_IFNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEvEEEEEclES4_SC_ + 72
73  RealmSyncDemo                       0x0000000102ed04b0 _ZN8facebook5react11JSIExecutor12callFunctionERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RKN5folly7dynamicE + 324
74  RealmSyncDemo                       0x0000000102e97d88 _ZZN8facebook5react16NativeToJsBridge12callFunctionEONSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEES9_ON5folly7dynamicEENK3$_2clEPNS0_10JSExecutorE + 636
75  RealmSyncDemo                       0x0000000102e97aec _ZNSt3__1L8__invokeIRZN8facebook5react16NativeToJsBridge12callFunctionEONS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEESA_ON5folly7dynamicEE3$_2JPNS2_10JSExecutorEEEEDTclscT_fp_spscT0_fp0_EEOSI_DpOSJ_ + 36
76  RealmSyncDemo                       0x0000000102e97a98 _ZNSt3__128__invoke_void_return_wrapperIvLb1EE6__callIJRZN8facebook5react16NativeToJsBridge12callFunctionEONS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEESC_ON5folly7dynamicEE3$_2PNS4_10JSExecutorEEEEvDpOT_ + 52
77  RealmSyncDemo                       0x0000000102e97a58 _ZNSt3__110__function12__alloc_funcIZN8facebook5react16NativeToJsBridge12callFunctionEONS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEESB_ON5folly7dynamicEE3$_2NS8_ISF_EEFvPNS3_10JSExecutorEEEclEOSI_ + 52
78  RealmSyncDemo                       0x0000000102e964fc _ZNSt3__110__function6__funcIZN8facebook5react16NativeToJsBridge12callFunctionEONS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEESB_ON5folly7dynamicEE3$_2NS8_ISF_EEFvPNS3_10JSExecutorEEEclEOSI_ + 52
79  RealmSyncDemo                       0x0000000102ea3fb8 _ZNKSt3__110__function12__value_funcIFvPN8facebook5react10JSExecutorEEEclEOS5_ + 84
80  RealmSyncDemo                       0x0000000102ea3f30 _ZNKSt3__18functionIFvPN8facebook5react10JSExecutorEEEclES4_ + 48
81  RealmSyncDemo                       0x0000000102ea3ef0 _ZZN8facebook5react16NativeToJsBridge18runOnExecutorQueueENSt3__18functionIFvPNS0_10JSExecutorEEEEENK3$_8clEv + 92
82  RealmSyncDemo                       0x0000000102ea3e74 _ZNSt3__1L8__invokeIRZN8facebook5react16NativeToJsBridge18runOnExecutorQueueENS_8functionIFvPNS2_10JSExecutorEEEEE3$_8JEEEDTclscT_fp_spscT0_fp0_EEOSB_DpOSC_ + 24
83  RealmSyncDemo                       0x0000000102ea3e2c _ZNSt3__128__invoke_void_return_wrapperIvLb1EE6__callIJRZN8facebook5react16NativeToJsBridge18runOnExecutorQueueENS_8functionIFvPNS4_10JSExecutorEEEEE3$_8EEEvDpOT_ + 28
84  RealmSyncDemo                       0x0000000102ea3e04 _ZNSt3__110__function12__alloc_funcIZN8facebook5react16NativeToJsBridge18runOnExecutorQueueENS_8functionIFvPNS3_10JSExecutorEEEEE3$_8NS_9allocatorISA_EEFvvEEclEv + 28
85  RealmSyncDemo                       0x0000000102ea2764 _ZNSt3__110__function6__funcIZN8facebook5react16NativeToJsBridge18runOnExecutorQueueENS_8functionIFvPNS3_10JSExecutorEEEEE3$_8NS_9allocatorISA_EEFvvEEclEv + 28
86  RealmSyncDemo                       0x0000000102f217e8 _ZNKSt3__110__function12__value_funcIFvvEEclEv + 60
87  RealmSyncDemo                       0x0000000102f216f8 _ZNKSt3__18functionIFvvEEclEv + 24
88  RealmSyncDemo                       0x0000000102ca8f70 _ZN8facebook5react17tryAndReturnErrorERKNSt3__18functionIFvvEEE + 24
89  RealmSyncDemo                       0x0000000102cd64a8 _ZN8facebook5react16RCTMessageThread7tryFuncERKNSt3__18functionIFvvEEE + 36
90  RealmSyncDemo                       0x0000000102cdc200 _ZZN8facebook5react16RCTMessageThread10runOnQueueEONSt3__18functionIFvvEEEENK3$_1clEv + 80
91  RealmSyncDemo                       0x0000000102cdc190 _ZNSt3__1L8__invokeIRZN8facebook5react16RCTMessageThread10runOnQueueEONS_8functionIFvvEEEE3$_1JEEEDTclscT_fp_spscT0_fp0_EEOSA_DpOSB_ + 24
92  RealmSyncDemo                       0x0000000102cdc148 _ZNSt3__128__invoke_void_return_wrapperIvLb1EE6__callIJRZN8facebook5react16RCTMessageThread10runOnQueueEONS_8functionIFvvEEEE3$_1EEEvDpOT_ + 28
93  RealmSyncDemo                       0x0000000102cdc120 _ZNSt3__110__function12__alloc_funcIZN8facebook5react16RCTMessageThread10runOnQueueEONS_8functionIFvvEEEE3$_1NS_9allocatorIS9_EES6_EclEv + 28
94  RealmSyncDemo                       0x0000000102cdab84 _ZNSt3__110__function6__funcIZN8facebook5react16RCTMessageThread10runOnQueueEONS_8functionIFvvEEEE3$_1NS_9allocatorIS9_EES6_EclEv + 28
95  RealmSyncDemo                       0x0000000102f217e8 _ZNKSt3__110__function12__value_funcIFvvEEclEv + 60
96  RealmSyncDemo                       0x0000000102f216f8 _ZNKSt3__18functionIFvvEEclEv + 24
97  RealmSyncDemo                       0x0000000102cd6204 ___ZN8facebook5react16RCTMessageThread8runAsyncENSt3__18functionIFvvEEE_block_invoke + 48
98  CoreFoundation                      0x0000000180361f94 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 20
99  CoreFoundation                      0x0000000180361268 __CFRunLoopDoBlocks + 408
100 CoreFoundation                      0x000000018035ba04 __CFRunLoopRun + 724
101 CoreFoundation                      0x000000018035b218 CFRunLoopRunSpecific + 572
102 RealmSyncDemo                       0x0000000102c7a8c8 +[RCTCxxBridge runRunLoop] + 764
103 Foundation                          0x0000000180851578 __NSThread__start__ + 792
104 libsystem_pthread.dylib             0x00000001cc0b16c8 _pthread_start + 116
105 libsystem_pthread.dylib             0x00000001cc0ac910 thread_start + 8.]

Can you reproduce the bug?

Yes, always

Reproduction Steps

open App.tsx and either removing or adding path makes it run or crash.

const RealmContext = createRealmContext({
	schema: [],
	// This line crashes the app with sync.
	path: 'sync.realm',
});

Crash happens after realm.logIn()

Version

10.19.1

What SDK flavour are you using?

Atlas App Services (auth, functions, etc.)

Are you using encryption?

No, not using encryption

Platform OS and version(s)

iOS 15.5

Build environment

System:
OS: macOS 12.4
CPU: (10) arm64 Apple M1 Pro
Memory: 105.23 MB / 16.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 17.9.0 - ~/.volta/tools/image/node/17.9.0/bin/node
Yarn: 1.22.18 - ~/.volta/tools/image/yarn/1.22.18/bin/yarn
npm: 8.5.5 - ~/.volta/tools/image/node/17.9.0/bin/npm
Watchman: 2022.03.21.00 - /opt/homebrew/bin/watchman
Managers:
CocoaPods: 1.11.3 - /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 21.4, iOS 15.5, macOS 12.3, tvOS 15.4, watchOS 8.5
Android SDK:
Android NDK: 23.0.7344513-beta4
IDEs:
Android Studio: Chipmunk 2021.2.1 Patch 1 Chipmunk 2021.2.1 Patch 1
Xcode: 13.4.1/13F100 - /usr/bin/xcodebuild
Languages:
Java: 18.0.1 - /Users/username/.jenv/shims/javac
npmPackages:
@react-native-community/cli: Not Found
react: 17.0.2 => 17.0.2
react-native: 0.68.2 => 0.68.2
react-native-macos: Not Found
npmGlobalPackages:
react-native: Not Found

Cocoapods version

1.11.3

@tomduncalf
Copy link
Contributor

Thanks for the report @rogerkerse, and for the reproduction repo. I can confirm I see the same issue here. I'll do some investigation into the root cause and let you know more when I do.

@tomduncalf
Copy link
Contributor

Hey @rogerkerse, I've had a closer look at your example and the issue here is that you are initially opening sync.realm as a non-synced Realm, then after the timeout fires, you are reopening the same file as a synced Realm, which is not supported unless you convert the non-synced Realm to a synced Realm first. It works when you do not specify a path because Realm will use a different default filename for the synced vs non-synced Realm.

Do you actually want to open the same Realm file as non-synced and synced? If so, I believe you need to use writeCopyTo to convert the local Realm to a synced Realm. It might be that there's a better way to handle what you want to do though, please feel free to describe your use case in more detail and I can try to help.

@sync-by-unito sync-by-unito bot added the Waiting-For-Reporter Waiting for more information from the reporter before we can proceed label Jun 22, 2022
@rogerkerse
Copy link
Author

rogerkerse commented Jun 22, 2022

Well our situation is that app is usable logged in or logged out. Once user decides to log in, then we want to sync all data that he already produced or new data that he is going to produce.

Keeping 2 separate realms for that purpose makes it extremely complicated to handle. Explaining the scenario that I mean:

  1. App uses "local realm"
  2. User logs in
  3. We copy over all the data to "synced realm"
  4. We have to replace realm instance in all places in the app so no more data would be produced to the wrong realm.

@github-actions github-actions bot added Needs-Attention Reporter has responded. Review comment. and removed Waiting-For-Reporter Waiting for more information from the reporter before we can proceed labels Jun 22, 2022
@ZComwiz
Copy link

ZComwiz commented Jun 22, 2022

Yes, RealmSync does not conform to modern UX/onboarding standards where a user may want to experience the app before logging in. Thats why we use Local Realm and built our own syncing logic from scratch. We would prefer to switch to Realm's solution, but it simply is too complicated currently.

We use a local realm that awaits user login. Then we even give the user the option if they want to have their data synced to the cloud. If they consent, we sync the current state of the db and start version tracking from there. I'm sure Realm Sync can achieve the same thing easily by considering all data entered into a synced realm as offline data until credentials are provided (same behavior as if the device is in airplane mode).

@bmunkholm
Copy link
Contributor

@ZComwiz We hare very recently made an option to convert the local realm to a synced realm for this particular use case (writeCopyTo) as @tomduncalf described. I assume that option wasn't available when you ran into the issue? It's definitely a use case we want to support, so feedback on how that solution works is appreciated.

@tomduncalf
Copy link
Contributor

@rogerkerse, it sounds like you would need to use writeCopyTo in this situation.

I am double checking with my colleague who implemented the feature, but I think the way to use it would be to open one Realm as a local Realm, then when the user logs in, write a copy of this Realm to a new, synced Realm.

I've created an example using our Node.js API here: https://github.com/tomduncalf/realm_4659_path_crashes_sync_node/blob/main/app.js, you can see that initially we open a local Realm, local.realm, then when the user logs in, we convert it to a synced Realm, sync.realm, and then reopen it with the new sync config.

Please let me know if anything is unclear or if you need more assistance with this!

@sync-by-unito sync-by-unito bot added Waiting-For-Reporter Waiting for more information from the reporter before we can proceed and removed Needs-Attention Reporter has responded. Review comment. labels Jun 23, 2022
@kneth
Copy link
Contributor

kneth commented Jul 8, 2022

@rogerkerse Did you have a chance to try the suggestion outline above?

@sync-by-unito sync-by-unito bot added the More-information-needed More information is needed to progress. The issue will close automatically in 2 weeks. label Jul 8, 2022
@rogerkerse
Copy link
Author

rogerkerse commented Jul 11, 2022

@rogerkerse Did you have a chance to try the suggestion outline above?

Trying to implement it in real world scenario but getting <RealmProvider> and RealmContext to dynamically switch out is a headache. I'll keep you posted if I arrive at some success. Tho right now it seems to be more pain than benefit. I would have expected database framework to have done it internally.

@github-actions github-actions bot added Needs-Attention Reporter has responded. Review comment. and removed Waiting-For-Reporter Waiting for more information from the reporter before we can proceed labels Jul 11, 2022
@tomduncalf
Copy link
Contributor

@rogerkerse Would it be helpful if we provided an example of doing the same using Realm React? I didn't realise you were using React Native when I provided my example

@rogerkerse
Copy link
Author

@tomduncalf yes that would be extremely helpful to see in react-native (on the fly switching out RealmContext, useQuery etc.), thank you

@sync-by-unito sync-by-unito bot removed the Needs-Attention Reporter has responded. Review comment. label Jul 13, 2022
@ZComwiz
Copy link

ZComwiz commented Jul 20, 2022

@rogerkerse, good luck. In the real world this task is riddled with race conditions. I look forward to seeing what the realm team proposes, but this should just be a boolean on realm directly that should handle offline and online storage. Its much easier to do on the C level / managing the web-socket connection as a parameter than for us to manually throw data around on the front end, but I don't know how Realm implemented Sync.

@tomduncalf
Copy link
Contributor

@rogerkerse I'm still looking into this, you're right that it's non trivial with Realm React so I am trying to work out the best way to do this, and talking to the team about if we need to add additional functionality to support this flow. Sorry for the trouble!

@ZComwiz I'll chat to the team about your suggestion as I do agree this is somewhat complicated but there might be valid reasons for it being so. I'll get back to you with our thoughts, it might be an area where we can improve our API in future for sure.

@rogerkerse
Copy link
Author

Hey @tomduncalf is there any update on the issue? 😊

@ZComwiz
Copy link

ZComwiz commented Aug 24, 2022

@kneth @tomduncalf @bmunkholm, this is a major issue for our team. We have been working extensively on a work around, but it makes far more sense to work together to help you make a proper API.

Is there anything we can do to help move this along?

@takameyer
Copy link
Contributor

@ZComwiz @rogerkerse Just want to chime in here. Instead of migrating a local realm to sync when a user logs in, why not start with an anonymous user in a synced realm, and then link the user to an authorized one (email, oauth, etc) when they sign up?

We have documentation on this.

Also we are planning on making the migration from non-sync to synced a bit more intuitive.

@ZComwiz
Copy link

ZComwiz commented Aug 24, 2022

@takameyer thanks for your reply! Is it possible in that model to not sync certain collections until a user toggles a setting (keeping some objects purely local)?

@takameyer
Copy link
Contributor

@ZComwiz We don't support exactly what you are describing. If that’s something you need, please create a feature request and we can get it on our radar.

It is possible to pause sync, but this can't be done on a per model basis:
https://www.mongodb.com/docs/realm-sdks/js/latest/Realm.App.Sync.Session.html#pause

@ZComwiz
Copy link

ZComwiz commented Aug 24, 2022

In the pause() case, can you pause indefinitely until a user toggles a switch? Will records appear locally in their device? We don't need a collection by collection condition per say. We need to disable sync until a user explicitly enables it but we need them to have their local realm be populated in all cases for functionality purposes.

@takameyer
Copy link
Contributor

@ZComwiz That should theoretically work. Realm is offline first, so if sync is disabled, you would just be writing to a local realm. I can foresee a possible issue, that on app restart, it will attempt to sync that local data when the realm is opened.

Is there a reason you don't want the anonymous data in the cloud? You could create a cleanup trigger that purges anonymous user data after a period of time.

@ZComwiz
Copy link

ZComwiz commented Aug 24, 2022

@takameyer minimize data collection where possible if the user does not require it.

@kraenhansen
Copy link
Member

We investigated this as a team today and found the app needs a change to convert from a local to a synced Realm.

Most notably:

  • We changed the path of the Realm config given to createRealmContext to keep it separate from the synced Realm.
  • We grab a reference to the local Realm using the realmRef prop on RealmProvider to enable calling writeCopyTo on it.
  • We changed from syncConfig to config (of type Configuration) and set a value when the user gets authenticated. When that config gets a value and we check if the sync.realm exists and if it doesn't we call the writeCopyTo method to convert the local Realm to a synced Realm, before the RealmProvider gets a chance to open the Realm.

We acknowledge that the process for upgrading a local to a synced Realm is a bit involved and we're tracking this issue to improve the experience: #4334.

Please see our suggestions applied below.
If you keep experiencing the issue, please reply and feel free to re-open or create another issue if something else pops up.

import React, {useMemo, useEffect, useCallback, useState, useRef} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import {AppProvider, createRealmContext, useApp} from '@realm/react';
import {Configuration, Credentials, SyncConfiguration} from 'realm';

const RealmContext = createRealmContext({
	schema: [],
	// This line crashes the app with sync.
	path: 'local.realm',
});

const {RealmProvider} = RealmContext;

const MONGO_ATLAS_APP_ID = '---'; // Change to your mongo atlas app id

const styles = StyleSheet.create({
	container: {
		flex: 1,
		justifyContent: 'center',
		alignItems: 'center',
		backgroundColor: 'lightblue',
	},
});

const AppComponent = () => {
	const realmApp = useApp();
	const [user, setUser] = useState<Realm.User<any>>();
	const realm = useRef<Realm>(null);

	const config: Configuration | undefined = useMemo(
		() =>
			user
				? {path: 'sync.realm', sync: {flexible: true, user: user}}
				: undefined,
		[user],
	);

	const loginToRealm = useCallback(async () => {
		// Waiting 2 seconds until login as a test simulating logging in later in the app's user flow
		await new Promise(resolve => setTimeout(resolve, 2000));
		const credentials = Credentials.anonymous();
		try {
			const realmUser = await realmApp.logIn(credentials);
			console.log('Successfully logged in!', realmUser.id);
			setUser(realmUser);
		} catch (error) {
			console.error('Failed to log in', (error as any).message);
		}
	}, [realmApp]);

	useEffect(() => {
		loginToRealm();
	}, [loginToRealm]);

	if (config && !Realm.exists(config) && realm.current) {
		console.log(`Converting ${realm.current.path} to a synced Realm`);
		// We need to convert the local realm into a synced Realm before opening it
		realm.current.writeCopyTo(config);
	}

	return (
		<RealmProvider {...config} realmRef={realm}>
			<View style={styles.container}>
				<Text>User {user?.id ?? 'not logged in'}</Text>
			</View>
		</RealmProvider>
	);
};

const App = () => {
	return (
		<AppProvider id={MONGO_ATLAS_APP_ID}>
			<AppComponent />
		</AppProvider>
	);
};

export default App;

@kraenhansen kraenhansen closed this as not planned Won't fix, can't repro, duplicate, stale Aug 25, 2022
@soliloquyx
Copy link

@kraenhansen I’ve been trying to implement your solution, but unfortunately running into problems with setting up a subscription. This is the error that I'm getting after logging in:

Error:

Client attempted a write that is outside of permissions or query filters; it has been reverted (ProtocolErrorCode=231)
Details:
{
  "Contact": {
    "0.8426483083351229_synced": "cannot write to table \"Contact\" before opening a subscription on it"
  }
}
Function Call Location:
IE
Remote IP Address:
213.35.181.75
SDK:
ios vRealmJS/10.19.1
Platform Version:
15.4

It seems that the subscription doesn't exist at the time and so the write gets reverted. Can you help us by pointing out a way to get past this?

Also, what about the data from local realm, that we want to carry over to the synced realm, but don't want to sync with the server? Our app has the option to turn off cloud syncing. Thus, user can limit what data gets synced, but we still want to store some information about their account. Is there any way to implement this?

My code demo: https://github.com/soliloquyx/realm-sync-demo-1

@kneth
Copy link
Contributor

kneth commented Sep 8, 2022

@soliloquyx We have recently discovered that converting a local Realm to a flexible sync Realm is not yet supported: realm/realm-core#5798

It means that you will have to copy objects from your local Realm to your flexible sync Realm.

@ZComwiz
Copy link

ZComwiz commented Sep 8, 2022

@kneth, has the realm team tried talking to some of their MDB customers to understand their use cases? The current implementation of Atlas Sync Realm seems pretty out of touch with the needs of modern day mobile apps. For instance, if an app developer wants to implement a task app, good UX may let them use the app and start adding objects to realm, but only sign in to save their data to the cloud or share it with colleagues. That would delay user login to an unknown time in the app life cycle and while it may be necessary for Mongo Atlas to set the owner of those documents, Realm should be able to persist data locally until being logged in which will give app developers a lot more flexibility to create proper UX flows that do not force a user to sign in before they understand more about the app they are using and if they feel comfortable letting that app handle their data on the cloud.

I'd love to chat with your team more and give some references to design patterns that should be supported that we use in industry developed at UC Berkeley and Stanford.

@ianpward
Copy link

ianpward commented Sep 8, 2022

@ZComwiz Product for Realm here. Yes - we speak to users and customers all the time. I'm always happy to have a call and discuss your app, company, and use cases you'd like to support. You can email me at [email protected] and we can setup a time to talk.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
@sync-by-unito sync-by-unito bot closed this as completed Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
More-information-needed More information is needed to progress. The issue will close automatically in 2 weeks. O-Community T-Bug
Projects
None yet
Development

No branches or pull requests

9 participants