Realm Swift Tutorial failing offline-first usage

There’s no difference in when the connection is established or when syncing starts depending on how you open it. There isn’t really anything to “force”. We continuously hold an open connection when possible and while online there’s no polling involved; the server just sends the device data whenever there’s anything to send. When connecting fails we do have automatic backoff to avoid killing the device’s battery, but we use a network reachability observer to immediately reconnect when the OS notifies us that the networking state has changed.

@Sebastian_Dwornik - oops I had the wrong format in that snippet, those are meant to be properties of the sync config - I just corrected it.

Hi Duncan,

I can’t seem to setup SyncConfiguration within my realm config using Swift, like you did.

Below is a snippet of my database layer code.

extension DatabaseLayer {
    // MARK: - DB setup

    private var userRealmFile: URL {
        let fullURLpath = userAppDirectory.appendingPathComponent(DALconfig.realmStoreName)
        return fullURLpath
    }

    private var realmConfig: Realm.Configuration {

        var config = Realm.Configuration(
//            syncConfiguration: SyncConfiguration

//        let syncConfig = RLMSyncConfiguration(user: app.currentUser!, partitionValue: app.currentUser?.id, stopPolicy: .immediately)

        let syncCon = app.currentUser?.configuration(partitionValue: app.currentUser!.id)
//        syncCon?.syncConfiguration?.user

//        config.syncConfiguration?.user = app.currentUser!.id
        config.syncConfiguration = SyncConfiguration(Self)



        config.fileURL = userRealmFile

        return config
    }


    func getDatabase() -> Realm? {
        do {
            return try Realm(configuration: realmConfig)
        } catch let error {
            DDLogError("Database error: \(error)")
            fatalError("Database error: \(error)")
        }
    }

May I ask what that code is for?

Are you trying to handle sync’ing locally when there is no network connection? Or is it for when the app disconnects after it was connected with .asyncOpen?

I am just trying to understand what additional steps are needed. Was this the/an answer?

I’m trying to simply modify my original realm code (listed above) to support syncing. Seems I can continue to call Realm() without having to rely on Realm.asyncOpen(), but need to configure the SyncConfiguration properties for it to work. Which I’m having some difficulty in accomplishing, in Swift.

That snipped was JavaScript not Swift.

It doesn’t look like RealmSwift SyncConfiguration supports those parameters.

https://docs.mongodb.com/realm-sdks/swift/latest/Structs/SyncConfiguration.html

Maybe @Thomas_Goyne can indicate if there is any plan to provide support in RealmSwift.

BTW V10. sync with MongoDB Realm is beta and I couldn’t get RealmSwift v10.x to work. Even the js sdk isync s still proving very unreliable.

@Sebastian_Dwornik Did you see my code snippet toward the top of the thread?

The code I posted in the func handleLocalConnection() is what’s needed and what we successfully use.

You could move that to a Singleton if you want or just make it a function you call throughout the app.

Thank you @Jay for the reminder, I think I finally got something working with:

private var realmConfig: Realm.Configuration {
    var userConfig = app.currentUser!.configuration(partitionValue: "user=\(app.currentUser!.id)", cancelAsyncOpenOnNonFatalErrors: true)

    userConfig.schemaVersion = DALconfig.DatabaseSchemaVersion
    userConfig.migrationBlock = { ... }
    userConfig.shouldCompactOnLaunch = { ... }

    return userConfig
}


func getDatabase() -> Realm? {
    do {
        return try Realm(configuration: realmConfig)
    } catch let error {
        DDLogError("Database error: \(error)")
        fatalError("Database error: \(error)")
    }
}


// MARK: - Low-level CRUD

func createOrUpdateAll<T: Object>(with objects: [T], update: Bool = true) {
    do {
        let database = self.getDatabase()
        try database?.write {
            database?.add(objects, update: update ? .all : .error)
        }
    } catch let error {
        DDLogError("Database error: \(error)")
        fatalError("Database error: \(error)")
    }
}

Then in my VC I can test with:

app.login(credentials: Credentials.emailPassword(email: appSession.userProfile.email,
                                                 password: appSession.userProfile.password)) { [weak self] (result) in
        DispatchQueue.main.async {
            switch result {
            case .failure(let error):
                DDLogError("Login failed: \(error)")
                return

            case .success(let user):    // RLMUser
                let car = RLMCar(partitionKey: "user=\(user.id)")
                car.brand = "Subaru"
                car.colour = "black"

                RLMCar().createOrUpdateAll(with: [car])
            }
        }
    }


I’ll add some error checking later. These are just core tests for the moment as I figure things out.

I’m still trying to wrap my head around realm objects and partitioning.

Why are you bothering with the cancelAsyncOpenOnNonFatalErrors parameter - you are not using Realm.asyncOpen() ?

Guess I’m just trying to figure things out, poking around everywhere. But have a better understanding of the realm state along with asyncOpen.

I finally did get things to sync last night, but my tinkering eventually got me into a crashing state on the mobile side with: Multiple sync agents attempted to join the same session

I couldn’t resolve it without wiping the app. I’m going to try to see if I can replicate it today as to what happened.

Finally found the culprit with my crashing issue re:
terminating with uncaught exception of type realm::MultipleSyncAgents: Multiple sync agents attempted to join the same session

I’m used to having MongoDB Realm Studio open to view my local realm db in action. Which is fine when it’s not a synced realm.

But a synced realm occupies a connection to the server, and apparently, when I restart my app in the simulator and it tries to re-connect with the synced realm server, the interference of an existing MongoDB Realm Studio connection denies the app to re-open the realm. And crashes with an exception.

By simply closing MongoDB Realm Studio, my app can reconnect and reopen the synced realm again.

Kind of a nuisance now though, as I enjoy leaving the MongoDB Realm Studio open in the background and switching to it for visual validation of DB work. ¯\(ツ)

Unless there’s a workaround? :thinking:

As far as I know there is no way you can open a synced realm with two clients unless those two clients have their own instances of the synced realm. I don’t believe MongoDB Realm Studio allows you to open a synced realm yet.

@Duncan_Groenewald and @Sebastian_Dwornik

Starting with RealmStudio 10.0.0 (10.1.0 now), sync’d realms can be opened and edited with Realm Studio with no problem.

Additionally, you can open a Sync’d Realm with Realm Studio as well as have it opened in the app - we do it all of the time.

Keep in mind though, that when working with sync’d Realms, the file structure is different than a local only Realm, which is typically single file of default.realm or whatever you choose to call it.

Sync’d realm files are stored by Partition with each partition being it’s own file.

There may be some differences when using the simulator however, everything we do is macOS based so we have not tried it with the simulator.

1 Like

@Jay - what am I missing, I have MongoDB Realm Studio 10.1.1 and there is no option to open a MongoDB Synced Realm only the option to open a local realm file ?

To open a synced realm I would expect to need to enter a MongoDB Realm app appId and to log in using some credentials.

The .realm file that is created within the app’s sandbox folder space is the sync’d realm that MongoDB Realm Studio opens and detects its sync connection. There is no UI to auth a synced realm, other than using the SDK within your app.

@Duncan_Groenewald I get the confusion - it’s partially how things are named and then how those names conceptually apply.

As @Sebastian_Dwornik mentioned, there is no function of ‘opening a realm on the server’ - the local realm file ‘represents’ what’s on the server and generally will be an exact copy - so if you use Realm Studio to open a Realm file that is set to be sync’d e.g. A sync’d realm file, if you make changes, those changes will be sync’d up to the server at some point.

The key is that Realm is a local first - sync second - database.

I think Firebase is a good contrast as it’s an online first database with support for local persistence. You can really only make changes on the server first and then that sync’s with the app later. So it’s an opposite pattern.

OK, I thought that Sync Realm files did not support being opened from two separate processes at the same time but that local realm files did. I am sure I read that in a post from one of you guys here or in GitHub.

In the older version of Realm Studio you would connect to the Realm Cloud and Realm Studio would download its own local realm file. You could run another app on the same computer and connect to Realm Cloud and it would do the same - creating essentially another copy of the synced realm file on the local computer.

Are you saying that now one can open the same local synced realm file with both the native app and MongoDB Realm Studio at the same time and perform updates from either client. Or can you only open the synced realm file from one client application at a time.

Also that would mean that you can’t open a NEW synced realm from MongoDB Realm Studio and get it to download a copy of the database since there is no UI to connect to MongoDB Realm App in Atlas - like the old version of Realm Studio would do if you connected to the Realm Cloud.

@Duncan_Groenewald I think things are a bit more transparent now. Yes, you can open any Realm file with Realm Studio (remembering that ALL realm files are LOCAL files, Realm is a local first database) and also have it opened in an app.

Here’s an example using the Task Tracker app (which sync’d to the server).

In the first screen shot, we open our Task Tracker app which shows four tasks, and then also open that same file with Realm Browser

Then in Realm Browser, we add a Task (step 1 in the middle). Noting that as soon as that’s saved, it shows up in the Task Tracker app (step 2, which is all local) and then a moment later, it shows up in the Realm Console (step 3).

Well, a new Sync’d realm would already have a local file and that’s what you would open with Realm Studio. Remember that Sync doesn’t exist until well, it’s sync’s. Otherwise it’s just data stored in the cloud.

Now, if what you’re after is to be able to connect Realm Studio to the data stored in the cloud, it doesn’t do that currently (as far as I know) and I would guess there’s a technical reason; If you look at the data stored in the cloud it’s organized in collections by ‘partitions’ whereas local files have each Realm (partition) stored as a separate file. It would probably take a re-write for Realm Studio to access cloud data in that way.

OK, cool thanks.

Usually we test by running a new synced realm client and connecting to the cloud system. That way we are sure the entire round trip is happening rather than just local commits.

With the old version of Realm Studio it lists all the realms (“partitions”) in the cloud and you select the one you want to open. When you open the realm it opens in a separate window and you can open multiple realms in separate windows directly from the cloud. I guess now one would have to use some other client for that initial connection to create the synced realm file from the cloud before using Realm Studio.

Also with the v4 and v5 Realm SDK you would get an exception if you tried to open a local synced realm file with two separate apps or processes at the same time although I do recall some discussion about that changing in the future.

Useful to know things have changed as I don’t recall seeing any documentation that describes these differences. Still trying to figure out what all the MongoDB Realm sync error messages mean and which we need to action and which we can safely ignore.

Cheers.

@Duncan_Groenewald - We worked with Realm Cloud (the legacy one) for a long time, actually since its inception and it was different for sure.

At a high level, the key difference is that back in the day, there were no partitions - all of the data was stored in a single Realm File locally (or multiple files if YOU choose to separate them) and the Cloud storage emulated that structure. e.g. all objects of all kinds were stored ‘in the same place’ both locally and in the cloud.

With MongoDB Realm, that had to be changed to make the client files more align with MongoDB cloud storage as their server structure was ‘different’.

With MongoDB Realm, each partition is it’s own Realm File (locally) and they are separated logically by partition, which we are finding is not an issue.