Handling Client Reset with Flexible Device Sync

We’re looking to release Device Sync to prod very shortly for the first time but are struggling/want to clarify how the client reset process should work when using Flexible Device Sync - not partition based.
The documentation here states you can set .discardLocal for a partition based sync which is what we want to do, however for a flexible sync configuration that doesn’t seem to be possible.

How can you set the equivalent to .discardLocal for Flexible device sync, or is this not possible?

If it’s not possible, is the below the expected correct setup to handle a Client Reset?


class RealmManager: ObservableObject {

    let app: App

    @Published var realmError: Error?
    @Published var realm: Realm?
    @Published var realmUser: RealmSwift.User?
    @Published var configuration: Realm.Configuration?

    init() {
        self.app = App(id: APP_ID)
        
        self.app.syncManager.errorHandler = { error, _ in
            guard let syncError = error as? SyncError else {
                return
            }
            switch syncError.code {
            case .clientResetError:
                if let (_, clientResetToken) = syncError.clientResetInfo() {
                    self.cleanUpRealm()
                    
                    SyncSession.immediatelyHandleError(clientResetToken, syncManager: self.app.syncManager)
                }
            default:
                break
            }
        }
    }
    
    @MainActor
    func initialize() async throws {
        realm?.invalidate()
        realm = nil
        realmUser = nil
        
        realmUser = try await login()
        
        self.configuration = realmUser?.flexibleSyncConfiguration(initialSubscriptions: { subs in
            if subs.first(named: "user-connections") != nil {
                subs.first(named: "user-connections")?.updateQuery(toType: UserConnections.self) {
                    $0.user_id == userId
                }
            } else {
                subs.append(QuerySubscription<UserConnections>(name: "user-connections") {
                    $0.user_id == userId
                })
            }
        }, rerunOnOpen: true)
        
        do {
            self.realm = try await Realm(configuration: self.configuration!, downloadBeforeOpen: .always)
        } catch {
            self.cleanUpRealm()
            self.realmError = OutsideRealmError.failedToConfigureRealm
        }
    }
    
    func cleanUpRealm() {
        realm?.invalidate()
        realm = nil
        realmUser = nil
        
        // Deleting immediately doesn't work, introduce a small wait
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
            do {
                if let configuration = self?.configuration {
                    _ = try Realm.deleteFiles(for: configuration)
                }
            } catch {
                
            }
        }
    }
}

1 Like

Hi Ryan,

In Latest Realm swift SDK v 10.35.0 it is supported.
Please refactor the Initialisation like below. It will work fine.

self.configuration = realmUser?.flexibleSyncConfiguration(clientResetMode: .discardUnsyncedChanges(beforeReset: { before in
                debugPrint("##### beforeReset Master Realms affected with Client reset - beforeReset :: \(String(describing: before.configuration.fileURL))")
            }, afterReset: { before, after in
                debugPrint("#####  afterReset Master Realms affected with Client reset - before :: \(String(describing: before.configuration.fileURL))")
                debugPrint("#####  afterReset Master Realms affected with Client reset - after  \(String(describing: after.configuration.fileURL))")
            }), initialSubscriptions: { subs in
                if subs.first(named: "user-connections") != nil {
                    subs.first(named: "user-connections")?.updateQuery(toType: UserConnections.self) {
                        $0.user_id == userId
                    }
                } else {
                    subs.append(QuerySubscription<UserConnections>(name: "user-connections") {
                        $0.user_id == userId
                    })
                }
            }, rerunOnOpen: true)

Thanks,
Seshu