realm-dart
realm-dart copied to clipboard
syncErrorHandler - provide better details in SyncError
I'm using the flutter_flexible_sync
example as the basis of a POC I'm working on, and after adding sync capabilities with Atlas, I'm not able to make the app work in offline mode.
Am I doing something wrong?
This is the code I'm using to create the Realm
object.
Future<Realm> createRealm(String appId) async {
final user = await App(AppConfiguration(appId)).logIn(
Credentials.anonymous(),
);
final realm = Realm(
Configuration.flexibleSync(
user,
[
// ...
],
),
);
print("Created local realm db at: ${realm.config.path}");
realm.subscriptions.update((mutableSubscriptions) {
mutableSubscriptions.add(realm.all<Car>());
mutableSubscriptions.add(realm.all<Person>());
});
await realm.subscriptions.waitForSynchronization();
print("Syncronization completed for realm: ${realm.config.path}");
return realm;
}
And this is the issue generated when trying to launch the app in offline mode:
flutter: [INFO] Realm: Connection[1]: Session[1]: client_reset_config = false, Realm exists = true, client reset = false
flutter: [ERROR] Realm: Failed to resolve 'ws.realm.mongodb.com:443': Host not found (authoritative)
Hello @jesusrp98,
Sorry we delayed the answer.
The flexible sync realm can work offline. The error you see is just a background warning and it does not crash the application.
It is the line
await realm.subscriptions.waitForSynchronization()
that prevents your code from continuing to work with the offline realm.
Use this method waitForSynchronization
only in case you insist to sync all data before to continue.
Hope this will help.
Hi @desistefanova
So before calling waitForSynchronization()
I should check whether there's internet available right? If there's no internet, that function should not be called, and everything should work offline, right?
Generally speaking, you don't need to recreate the subscriptions every time you run the app as those are persisted. You could do something like:
final cars = realm.all<Car>();
final people = realm.all<Person>();
if (realm.subscriptions.find(cars) == null || realm.subscriptions.find(people) == null)
{
realm.subscriptions.update((mutableSubscriptions) {
mutableSubscriptions.add(cars);
mutableSubscriptions.add(people);
});
await realm.subscriptions.waitForSynchronization();
}
@nirinchev @desistefanova
So, in the end, the realm.subscriptions.update
should only be make if realm cant find existing subscriptions, since they persist over sessions.
And for sync using Atlas, I need to make sure that I'm connected to the internet (for example using the connectivity_plus
plugin) when waiting for sync in the main
function:
final connection = await Connectivity().checkConnectivity();
if (connection != ConnectivityResult.none)
await realm.subscriptions.waitForSynchronization();
And for when adding new data to the database:
realm.write(() {
realm.add(
Car(
// ...
);
});
final connection = await Connectivity().checkConnectivity();
if (connection != ConnectivityResult.none) {
await MyApp.realm.syncSession.waitForUpload();
await MyApp.realm.subscriptions.waitForSynchronization();
}
}
You only need to call waitForSynchronization
when you update the subscriptions - once the subscriptions have successfully bootstrapped (sent to the server and matching data sent to the client), it'll be a no-op.
@nirinchev So when adding a new object to the database, calling waitForSynchronization()
is not necessary right? Only when updating realm subscriptions inside the main
function.
final connection = await Connectivity().checkConnectivity();
if (connection != ConnectivityResult.none) {
await MyApp.realm.syncSession.waitForUpload();
// await MyApp.realm.subscriptions.waitForSynchronization(); <- This is not necessary for writting data
}
@jesusrp98 I created a new PR for that sample flutter_flexible_sync
. This PR handles your case when you are trying to run the application without having a connectivity. I hope it will help you. I'm calling waitForUpload
even if there is no connectivity in order to refresh the state automatically after the connection is restored. You can use syncErrorHandler
of Configuration.flexibleSync
to verify whether the connection is lost. Probably we can provide better details in SyncError, so that you can handle all kind of communication errors.
@jesusrp98 You can find the answer in the PR comments https://github.com/realm/realm-dart-samples/pull/14#issuecomment-1310915520
Good morning everyone!
First, forgive me for any language errors.
I would like to ask some questions regarding the best way to use the Realm library.
I'm currently facing the same timing problem reported by the issue, but it happens randomly. Because of this, I would like to know if they would have any guidance to be able to give better integrity to the data.
Currently, when the user logs in, we send the user to a synchronization interface (to indicate the flow) and after completion, we redirect to the main interface. Until this process everything is ok, but this action occurs only once after login. If the user closes the app and resumes using it, the subscriptions resource is not called again.
When the same information is manipulated on different devices, sometimes the app crashes and closes abruptly (but when the user returns to the app, the record is shown), or the record does not update on one of the devices.
The question would be as follows:
after recording/editing/deleting the information, would there be a need to call the subscriptions in sequence?
A behavior that we also caught would be related to the deletion of some record (Atlas console, action in the app). When this occurs, a data integrity error is displayed stating that the record does not exist (but it is shown in the application). When the app runs again, the information is no longer displayed.
Would it be a good idea to have this flow of calling subscriptions to be able to update information at all times after recording/editing/deleting?
Thank you so much for your support and again I apologize for any issues. I'm still at the very beginning of using Realm (this is my first contact with the lib).
Hi @ffeliciodeveloper,
Welcome to the Realm community!
It is hard for me to imagine how the code of your app looks like. But if you are asking whether to call waitForSynchronization
each time after a create/update/delete operation, the answer is "You don't need to to this.". You can see this sample.
Updating the subscription should happen only once. After that the subscriptions are stored in the realm. That's why we recommend to update them only if they are not set, as it is shown in this example https://github.com/realm/realm-dart/issues/676#issuecomment-1164145219. waitForSynchronization
has to be called only in case there is a change in the subscriptions, i.e. you are changing the query that filters the data you want to sync.
According to your description I guess that the UI of your app is not refreshed in real time. Are you using a listener to the change notifications? You can see the example users_permissions and how the list is listening to the changes .
I hope this will help you! Feel free to ask if I haven't answered your questions?
Added new category SyncResolveError
for network or server errors. The error codes of type SyncResolveErrorCode
could be checked when receiving syncErrorHandler
attached to the configuration.