Skip to content

Commit

Permalink
DOCSP-32918: Document .reconnect() for Kotlin SDK (mongodb#3005)
Browse files Browse the repository at this point in the history
## Pull Request Info

Add `App.Sync.reconnect()` method to existing page

> NOTE: the related `app.sync.waitForSessionsToTerminate()` method is
purposefully omitted until it's confirmed to be working as expected and
ready to be documented

### Jira

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

### Staged Changes

- [Manage a Sync Session - Kotlin
SDK](https://docs-mongodbcom-staging.corp.mongodb.com/realm/docsworker-xlarge/docsp-32918-sync-reconnect/sdk/kotlin/sync/manage-sync-session/)

### 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)

---------

Co-authored-by: Dachary <dc@dacharycarey.com>
  • Loading branch information
cbullinger and dacharyc authored Sep 20, 2023
1 parent f970475 commit 8c8747a
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import kotlin.time.Duration.Companion.minutes

// :replace-start: {
// "terms": {
// "SyncTask": "Task"
// "SyncTask": "Task",
// "FLEXIBLE_APP_ID": "YOUR_APP_ID"
// }
// }
class ManageSyncSession : RealmTest() {
Expand Down Expand Up @@ -207,5 +208,57 @@ class ManageSyncSession : RealmTest() {
realm.close()
}
}

// NOTE: Can't test `.reconnect()` since it requires device reconnecting after going offline
@Test
fun appSyncSessionsTest() {
runBlocking {
// Most of this is commented out until `app.sync.waitForSessionsToTerminate()` is confirmed
// to be working as expected and can be documented

// :snippet-start: open-sync-session
val app = App.create(FLEXIBLE_APP_ID)
val user = app.login(credentials)
val config = SyncConfiguration.Builder(user, setOf(SyncTask::class))
.build()

// Open the synced realm
val realm = Realm.open(config)

// Sync session is now active
assertTrue(app.sync.hasSyncSessions) // :remove:

// ... do something with the synced realm

// :snippet-end:
// :snippet-start: app-sync-reconnect
app.sync.reconnect()
// :snippet-end:
user.delete()
realm.close()
app.close()

// val config1 = SyncConfiguration.Builder(user, setOf()).name("other.realm").build()
// val config2 = SyncConfiguration.Builder(user, setOf()).name("another.realm").build()
// val realm1 = Realm.open(config1)
// val realm2 = Realm.open(config2)
// assertTrue(
// // snippet-start
// app.sync.hasSyncSessions
// // snippet-end
// )
// realm1.close()
// realm2.close()
// assertTrue(realm1.isClosed())
// assertTrue(realm2.isClosed())
// // snippet-start
// app.sync.waitForSessionsToTerminate()
// // snippet-end
// assertFalse(app.sync.hasSyncSessions)
// app.close()
// Realm.deleteRealm(config1) // if I don't close app first, I get an IllegalStateException: [RLM_ERR_DELETE_OPENED_REALM]: Cannot delete files of an open Realm:
// Realm.deleteRealm(config2)
}
}
}
// :replace-end:
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,9 @@ open class RealmTest {
val TMP_PATH = "tmp"
val mainThreadSurrogate = newSingleThreadContext("UI thread")
val defaultRealmConfiguration = RealmConfiguration.Builder(setOf())
// :remove-start:
.inMemory()
.directory(TMP_PATH)
.name(getRandom())
// :remove-end:
.build()

suspend fun <T : Any?> Channel<T>.receiveOrFail(timeout: Duration = 30.seconds): T {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
app.sync.reconnect()
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
val app = App.create(YOUR_APP_ID)
val user = app.login(credentials)
val config = SyncConfiguration.Builder(user, setOf(Task::class))
.build()

// Open the synced realm
val realm = Realm.open(config)

// Sync session is now active

// ... do something with the synced realm

84 changes: 72 additions & 12 deletions source/sdk/kotlin/sync/manage-sync-session.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,46 @@ Manage a Sync Session - Kotlin SDK
:depth: 2
:class: singlecol

When you use :ref:`Flexible Sync <flexible-sync>`, the Realm Kotlin SDK syncs
data with Atlas in the background using a sync session. The sync session starts
whenever you open a synced realm.
This page describes sync sessions and how to manage them in an App using
Flexible Sync. For detailed information on Flexible Sync, refer to
:ref:`Atlas Device Sync <sync>` in the App Services documentation.

Sync Sessions
-------------

When you use Flexible Sync, the Realm Kotlin SDK syncs
data with Atlas in the background using a **sync session**. The sync
session starts whenever you :ref:`open a synced realm
<kotlin-open-a-synced-realm>`.

.. literalinclude:: /examples/generated/kotlin/ManageSyncSession.snippet.open-sync-session.kt
:language: kotlin

The sync session manages the following:

- Uploading and downloading changes to the realm
- Pausing and resuming sync
- Monitoring network connectivity

You can access the `SyncSession <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/index.html>`__
of any synced realm through the `realm.syncSession <{+kotlin-sync-prefix+}io.realm.kotlin.Realm/syncSession.html>`__
property.
You can access the `SyncSession
<{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/index.html>`__
of a single synced realm through the `realm.syncSession
<{+kotlin-sync-prefix+}io.realm.kotlin.Realm/syncSession.html>`__
property.

Prerequisites
-------------
Connection States vs. Session States
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Before you can manage your sync session state, you must perform the following:
The Kotlin SDK manages communication with App Services at two levels:

#. :ref:`Configure Flexible Sync on the Atlas App Services backend <enable-flexible-sync>`.
#. :ref:`Authenticate a user <kotlin-authenticate>` in your client app.
#. :ref:`Open the synced realm <kotlin-open-a-synced-realm>`.
- **connection state**: the state of the network connection between a client
device and your backend App.
- **session state**: a single user's synchronization state, which can be paused
and resumed in the SDK at will (refer to the
:ref:`<kotlin-pause-resume-sync>` section).

Both states determine whether a user's local changes sync to the backend. Synchronization only occurs when the
`SyncSession.ConnectionState <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-connection-state/index.html>`__ is ``CONNECTED`` and the `SyncSession.State <{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/-state/index.html>`__ is either ``ACTIVE`` or ``DYING``.

.. _kotlin-sync-wait-for-changes:

Expand Down Expand Up @@ -107,3 +125,45 @@ new and old ``ConnectionState`` from ``ConnectionStateChange``.

.. literalinclude:: /examples/generated/kotlin/ManageSyncSession.snippet.monitor-network-connection.kt
:language: kotlin

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

.. versionadded:: 1.11.0

Realm automatically detects when a device regains connectivity after being
offline and attempts to reconnect using an incremental backoff strategy.

In Kotlin SDK version 1.11.0 and later, you can choose to manually trigger a
reconnect attempt with the `App.Sync.reconnect()
<{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync/reconnect.html>`__
instead of waiting for the duration of the incremental backoff. This is
useful if you have a more accurate understanding of
the network conditions (for example, when monitoring network changes with the
``ConnectivityManager`` on Android) and don't want to rely on Realm's automatic
reconnect detection. The SDK also automatically calls this method when a device
toggles off airplane mode.

To manually trigger a reconnect attempt, call the `App.Sync.reconnect()
<{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync/reconnect.html>`__
method, which is accessed through the
`App.Sync
<{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync/index.html>`__
interface. Unlike `SyncSession
<{+kotlin-sync-prefix+}io.realm.kotlin.mongodb.sync/-sync-session/index.html>`__,
which lets you access a single realm sync session, the ``App.Sync`` interface
controls *all* sync sessions for your App.

.. literalinclude:: /examples/generated/kotlin/ManageSyncSession.snippet.app-sync-reconnect.kt
:language: kotlin

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

.. 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 ``App.Sync.reconnect()``
within that window, the Kotlin SDK does *not* attempt to reconnect.

0 comments on commit 8c8747a

Please sign in to comment.