Skip to content

Commit

Permalink
Swift: Add docs for SyncSession.reconnect() (#3062)
Browse files Browse the repository at this point in the history
## Pull Request Info

A few questions for a tech reviewer based on the similar docs in Kotlin:
- In Kotlin, we say "The SDK also automatically calls this method when a
device toggles off airplane mode" - is this accurate in the Swift SDK,
also? I didn't see anything special for this in the SDK PR so wondering
if this is something in Core?
- In Kotlin, we say "the SDK forces all sync sessions to attempt to
reconnect immediately" - is this also true in Swift, or is it forcing
only the `SyncSession` you call it on to reconnect? Does this change
with session multiplexing enabled/disabled?
- Kotlin has a callout about not being able to force a reconnection
within the socket read timeout duration - is this also true in Swift?
- It seems the [RLMSyncSession got docs for the new
method](https://www.mongodb.com/docs/realm-sdks/objc/latest/Classes/RLMSyncSession.html),
but [Swift's
SyncSession](https://www.mongodb.com/docs/realm-sdks/swift/latest/Extensions/SyncSession.html)
didn't. Could we add this, or am I looking in the wrong place?

### Jira

- https://jira.mongodb.org/browse/DOCSP-33926

### Staged Changes

- [Manage Sync
Sessions](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-33926/sdk/swift/sync/sync-session/)

The rest of the examples in the test file were still using
Partition-Based Sync, so I also updated those examples to FS. Those
examples are at:
- [Configure & Open a Synced
Realm](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/DOCSP-33926/sdk/swift/sync/configure-and-open-a-synced-realm/#download-changes-before-open)

### Reminder Checklist

If your PR modifies the docs, you might need to also update some
corresponding
pages. Check if completed or N/A.

- [x] Create Jira ticket for corresponding docs-app-services update(s),
if any
- [x] Checked/updated Admin API
- [x] Checked/updated CLI reference

### Review Guidelines


[REVIEWING.md](https://github.com/mongodb/docs-realm/blob/master/REVIEWING.md)
  • Loading branch information
dacharyc authored Nov 2, 2023
1 parent 8f7137a commit a0e50ac
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 52 deletions.
87 changes: 50 additions & 37 deletions examples/ios/Examples/Sync.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class Sync: AnonymouslyLoggedInTestCase {
if app.currentUser != nil {
return app.currentUser!
} else {
// Instantiate the app using your Realm app ID
let app = App(id: YOUR_APP_SERVICES_APP_ID)
// Instantiate the app using your App Services App ID
let app = App(id: APPID)
// Authenticate with the instance of the app that points
// to your backend. Here, we're using anonymous login.
let loggedInUser = try await app.login(credentials: Credentials.anonymous)
Expand All @@ -40,16 +40,12 @@ class Sync: AnonymouslyLoggedInTestCase {
func getRealm() async throws -> Realm {
// Get a logged-in app user
let user = try await getUser()
// Specify which data this authenticated user should
// be able to access.
let partitionValue = "some partition value"
// Store a configuration that consists of the current user,
// authenticated to this instance of your app, who should be
// able to access this data (partition).
var configuration = user.configuration(partitionValue: partitionValue)
// :remove-start:
configuration.objectTypes = [SyncExamples_Task.self]
// :remove-end:
// authenticated to this instance of your app,
// and what object types this database should manage.
var configuration = user.flexibleSyncConfiguration()
configuration.objectTypes = [FlexibleSync_Task.self, FlexibleSync_Team.self]

// Open a Realm with this configuration.
let realm = try await Realm(configuration: configuration)
print("Successfully opened realm: \(realm)")
Expand All @@ -58,44 +54,43 @@ class Sync: AnonymouslyLoggedInTestCase {

// Get a realm
let realm = try await getRealm()
// Do something with the realm
print("The open realm is: \(realm)")
// Add subscriptions and work with the realm
// :snippet-end:
expectation.fulfill()
wait(for: [expectation], timeout: 10)
await fulfillment(of: [expectation], timeout: 10, enforceOrder: true)
}

// :snippet-start: specify-download-behavior
func testSpecifyDownloadBehavior() async throws {
// :remove-start:
let expectation = XCTestExpectation(description: "it completes")
// :remove-end:
let app = App(id: YOUR_APP_SERVICES_APP_ID)
let user = try await app.login(credentials: Credentials.anonymous)
let partitionValue = "some partition value"
var configuration = user.configuration(partitionValue: partitionValue)
// :remove-start:
configuration.objectTypes = [SyncExamples_Task.self]
// :remove-end:
let realm = try await Realm(configuration: configuration, downloadBeforeOpen: .always) // :emphasize:
print("Successfully opened realm after downloading: \(realm)")
// :remove-start:
// :snippet-start: specify-download-behavior
func getRealmAfterDownloadingUpdates() async throws -> Realm {
let app = App(id: APPID)
let user = try await app.login(credentials: Credentials.anonymous)
var configuration = user.flexibleSyncConfiguration()
configuration.objectTypes = [FlexibleSync_Task.self, FlexibleSync_Team.self]

let realm = try await Realm(configuration: configuration, downloadBeforeOpen: .always) // :emphasize:
print("Successfully opened realm after downloading: \(realm)")
return realm
}

let realm = try await getRealmAfterDownloadingUpdates()
print("The open realm is: \(realm)")
// Add subscription and work with the realm
// :snippet-end:
expectation.fulfill()
wait(for: [expectation], timeout: 10)
// :remove-end:
await fulfillment(of: [expectation], timeout: 10, enforceOrder: true)
}
// :snippet-end:

func testPauseResumeSyncSession() {
let app = App(id: YOUR_APP_SERVICES_APP_ID)
// Log in...
let user = app.currentUser
let partitionValue = "some partition value"
var configuration = user!.configuration(partitionValue: partitionValue)
// :remove-start:
configuration.objectTypes = [SyncExamples_Task.self]
// :remove-end:
let syncedRealm = try! Realm(configuration: configuration)
func testPauseResumeSyncSession() async throws {
let app = App(id: APPID)
let user = try await app.login(credentials: Credentials.anonymous)
var configuration = user.flexibleSyncConfiguration()
configuration.objectTypes = [FlexibleSync_Task.self, FlexibleSync_Team.self]
let syncedRealm = try! await Realm(configuration: configuration)

// :snippet-start: pause-resume-sync-session
let syncSession = syncedRealm.syncSession!
Expand Down Expand Up @@ -138,6 +133,8 @@ class Sync: AnonymouslyLoggedInTestCase {
// :snippet-end:
}

// Leaving this example using Partition-Based Sync
// since progress notifications are currently only supported in PBS
func testCheckProgress() {
let app = App(id: YOUR_APP_SERVICES_APP_ID)
let user = app.currentUser
Expand Down Expand Up @@ -223,5 +220,21 @@ class Sync: AnonymouslyLoggedInTestCase {
}
// :snippet-end:
}

func testSyncSessionReconnect() async throws {
let app = App(id: YOUR_APP_SERVICES_APP_ID)
let user = try await app.login(credentials: Credentials.anonymous)
var configuration = user.flexibleSyncConfiguration()
configuration.objectTypes = [FlexibleSync_Task.self, FlexibleSync_Team.self]
let realm = try! await Realm(configuration: configuration)

// :snippet-start: sync-session-reconnect
let syncSession = realm.syncSession!

// Work with the realm. When you need to force the sync session to reconnect...
syncSession.reconnect()
// :snippet-end:

}
}
// :replace-end:
2 changes: 1 addition & 1 deletion examples/ios/RealmExamples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1471,7 +1471,7 @@
repositoryURL = "https://github.com/realm/realm-swift.git";
requirement = {
kind = exactVersion;
version = 10.43.0;
version = 10.44.0;
};
};
917CA79427ECADC200F9BDDC /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ func getUser() async throws -> User {
if app.currentUser != nil {
return app.currentUser!
} else {
// Instantiate the app using your Realm app ID
let app = App(id: YOUR_APP_SERVICES_APP_ID)
// Instantiate the app using your App Services App ID
let app = App(id: APPID)
// Authenticate with the instance of the app that points
// to your backend. Here, we're using anonymous login.
let loggedInUser = try await app.login(credentials: Credentials.anonymous)
Expand All @@ -19,13 +19,12 @@ func getUser() async throws -> User {
func getRealm() async throws -> Realm {
// Get a logged-in app user
let user = try await getUser()
// Specify which data this authenticated user should
// be able to access.
let partitionValue = "some partition value"
// Store a configuration that consists of the current user,
// authenticated to this instance of your app, who should be
// able to access this data (partition).
var configuration = user.configuration(partitionValue: partitionValue)
// authenticated to this instance of your app,
// and what object types this database should manage.
var configuration = user.flexibleSyncConfiguration()
configuration.objectTypes = [FlexibleSync_Task.self, FlexibleSync_Team.self]

// Open a Realm with this configuration.
let realm = try await Realm(configuration: configuration)
print("Successfully opened realm: \(realm)")
Expand All @@ -34,5 +33,5 @@ func getRealm() async throws -> Realm {

// Get a realm
let realm = try await getRealm()
// Do something with the realm
print("The open realm is: \(realm)")
// Add subscriptions and work with the realm
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
.. code-block:: swift
:emphasize-lines: 6
:emphasize-lines: 7
func testSpecifyDownloadBehavior() async throws {
let app = App(id: YOUR_REALM_APP_ID)
func getRealmAfterDownloadingUpdates() async throws -> Realm {
let app = App(id: APPID)
let user = try await app.login(credentials: Credentials.anonymous)
let partitionValue = "some partition value"
var configuration = user.configuration(partitionValue: partitionValue)
var configuration = user.flexibleSyncConfiguration()
configuration.objectTypes = [FlexibleSync_Task.self, FlexibleSync_Team.self]
let realm = try await Realm(configuration: configuration, downloadBeforeOpen: .always)
print("Successfully opened realm after downloading: \(realm)")
return realm
}
let realm = try await getRealmAfterDownloadingUpdates()
print("The open realm is: \(realm)")
// Add subscription and work with the realm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let syncSession = realm.syncSession!

// Work with the realm. When you need to force the sync session to reconnect...
syncSession.reconnect()
37 changes: 37 additions & 0 deletions source/sdk/swift/sync/sync-session.txt
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,40 @@ Check Upload & Download Progress for a Sync Session

.. literalinclude:: /examples/generated/code/start/Sync.snippet.check-progress.m
:language: objectivec

.. _ios-reconnect-sync-sessions:

Manually Reconnect All Sync Sessions
------------------------------------

.. versionadded:: 10.44.0

Realm automatically detects when a device regains connectivity after being
offline and attempts to reconnect using an incremental backoff strategy.
For example, on Apple platforms, Realm listens for network change notifications
and automatically triggers a reconnect immediately after receiving one.

In Swift SDK version 10.44.0 and later, you can choose to manually trigger a
reconnect attempt with ``SyncSession.reconnect()``
instead of waiting for the duration of the incremental backoff. This is
useful if you have a more accurate understanding of
the network conditions and don't want to rely on Realm's automatic
reconnect detection.

.. literalinclude:: /examples/generated/code/start/Sync.snippet.sync-session-reconnect.swift
:language: swift

When you call this method, the SDK forces all sync sessions to *attempt* to
reconnect immediately. This resets any timers used for incremental
backoff.

Calling this method does not guarantee the device can reconnect. If the SDK
gets a fatal error, or if the device is already connected or is trying to
connect, calling this method has no effect.

.. important:: Cannot Reconnect Within Socket Read Timeout Duration

Realm has an internal default socket read timeout of 2 minutes, where
Realm will time out if a read operation does not receive any data
within a 2-minute window. If you call ``SyncSession.reconnect()``
within that window, the Swift SDK does *not* attempt to reconnect.

0 comments on commit a0e50ac

Please sign in to comment.