Docs Menu
Docs Home
/ /
Atlas Device SDKs
/

Manage Sync Sessions

On this page

  • Get the Sync Session
  • Check the Network Connection
  • Check the Sync State
  • Pause or Resume a Sync Session
  • When to Pause a Sync Session
  • Wait for Changes to Upload or Download
  • Check Upload and Download Progress
  • Manually Reconnect All Sync Sessions

Opening a synced database starts a Sync session for that database. Atlas Device SDK provides methods to:

  • Check the network connection state.

  • Manually pause and resume a Sync session.

  • Wait for changes to upload or download.

  • Check upload or download progress.

  • Manually reconnect Sync sessions after a device has been offline.

You can also define the Sync connection behavior. App Services defaults to sharing a single connection to the server for all opened synced databases. The connection to the server is independent of the Sync session, and is based on the App Services user.

You can change the Sync connection behavior from the App client configuration.

You can use the member function get_sync_session() to get a sync_session object for any synced database. The SDK returns this object as an optional. It is a lightweight handle that you can pass around by value.

You can access the Sync Session through a synced Realm.

You can access the session of any synced database through the SyncSession.

After opening a synced database, you can access its sync session with the Realm.syncSession property.

You can access the SyncSession of a single synced database through the realm.syncSession property.

You can access the session of any synced database through the SyncSession.

You can access the SyncSession object on a synced Realm.

You can access the SyncSession on a synced Realm.

After opening a synced database, you can access its sync session with the Realm.syncSession property.

auto syncSession = realm.get_sync_session();
// The documentation does not currently have this code example in C#.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Dart.
// Please refer to the other languages or related pages for example code.
// The documentation does not have this code example in Java.
// Please refer to the other languages or related pages for example code.
const realm = await Realm.open(config);
const syncSession = realm.syncSession;
// The documentation does not currently have this code example in Kotlin.
// Please refer to the other languages or related pages for example code.
// The documentation does not have this code example in Kotlin for the Java SDK.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Objective-C.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Swift.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in TypeScript.
// Please refer to the other languages or related pages for example code.

The SDK's offline-first design means that you generally don't need to check the current network connection state. However, the SDK provides a connection state property if your app calls for some indication of connection state.

Check Connection State

To check the connection state, you can read the sync session instance's connection_state() property directly.

syncSession->connection_state();

The network connection state is distinct from the Device Sync connection state that you can check with the state() method. For more information about sync connection state, refer to the Check the Sync State documentation on this page.

Observe Connection State

You can also observe the connection state with the observe_connection_change() function. This function registers a callback that the SDK invokes when the underlying sync session changes its connection state.

auto connectionToken = syncSession->observe_connection_change(
[&](enum realm::sync_session::connection_state,
enum realm::sync_session::connection_state new_state) {
// Register a block to execute when connection state changes.
});

If you register a connection change listener, you can unregister it when you're done listening for changes. Call the sync session instance's unregister_connection_change_observer() method to unregister an observation token.

To check the connection state, you can read the Session instance's ConnectionState property. Its value is a ConnectionState enum that reflects the current state of the sync session's connection.

You can get the state of the current network connection with Session.connectionState. This returns a ConnectionState enum that contains the network connection's state, which is one of:

  • connected

  • disconnected

  • connecting

if (realm.syncSession.connectionState == ConnectionState.connected) {
// ... do stuff
}

Monitor the state of the network connection with Session.connectionStateChanges. This property returns a Stream of ConnectionStateChange objects that updates when the network connection changes. You can access the current and previous ConnectionState from ConnectionStateChange.

To check the current network connection, call getConnectionState() on your SyncSession.

You can also subscribe to connection changes on your SyncSession with addConnectionChangeListener()

To check the current state of the connection to the server, call the syncSession.connectionState() method.

You can check the network connection state through the SyncSession.ConnectionState. This is a property of type ConnectionState enum, whose possible values are:

  • DISCONNECTED

  • CONNECTING

  • CONNECTED

if (realm.syncSession.connectionState == ConnectionState.CONNECTED) {
Log.i("Connected to network")
// ... do something
}

Monitor the state of the network connection with connectionStateAsFlow. This property returns a Flow of ConnectionStateChange objects that updates when the network connection changes. You can access the new and old ConnectionState from ConnectionStateChange.

To check the current network connection, call getConnectionState() on your SyncSession.

You can also subscribe to connection changes on your SyncSession with addConnectionChangeListener()

To get the connection state of a SyncSession, set an event handler on the PropertyChanged event. The event handler is a standard .NET PropertyChangedEventHandler delegate that takes in a sender object and PropertyChangedEventArgs object.

In the event handler, cast the sender to a Session object and check if the event argument's PropertyName property is Session.ConnectionState. You can then get the ConnectionState value, which is one of the following:

  • Connecting

  • Connected

  • Disconnected

The following code demonstrates setting the event handler, casting the session object, and checking the Sync status:

To check the connection state, you can read the SyncSession instance's connectionState property directly.

This property is KVO-compliant, so you can observe changes using KVO or even Combine.

To check the current state of the connection to the server, call the syncSession.connectionState() method.

syncSession->unregister_connection_change_observer(connectionToken);
public void SetupRealm()
{
var appConfig = new AppConfiguration(myRealmAppId);
app = App.Create(appConfig);
user = app.LogInAsync(Credentials.Anonymous()).Result;
config = new PartitionSyncConfiguration("myPartition", user);
try
{
var realm = Realm.GetInstance(config);
var session = realm.SyncSession;
session.PropertyChanged += SyncSessionPropertyChanged!;
realm.Dispose();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void SyncSessionPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Session.ConnectionState))
{
var session = (Session)sender;
var currentState = session.ConnectionState;
if (currentState == ConnectionState.Connecting)
{
//session is connecting
}
if (currentState == ConnectionState.Connected)
{
//session is connected
}
if (currentState == ConnectionState.Disconnected)
{
//session has been disconnected
}
}
}
final connectionStream = realm.syncSession.connectionStateChanges;
late StreamSubscription streamListener;
streamListener = connectionStream.listen((connectionStateChange) {
if (connectionStateChange.current == ConnectionState.connected) {
print("Connected to Atlas Device Sync server");
streamListener.cancel();
}
});
Log.v("EXAMPLE", "Sync state: " + app.getSync().getSession(config).getConnectionState());
const config = {
schema: [DogSchema],
sync: {
user: app.currentUser,
partitionValue: "MyPartitionValue",
},
};
const realm = await Realm.open(config);
const connectionState = realm.syncSession?.connectionState;
val connectionFlow = realm.syncSession.connectionStateAsFlow()
connectionFlow.collect { ConnectionStateChange ->
if (ConnectionStateChange.newState == ConnectionState.CONNECTED) {
Log.i("Connected to Atlas Device Sync server")
}
}
Log.v("EXAMPLE", "Sync state: ${app.sync.getSession(config).connectionState}")
@interface MySyncSessionObserver: NSObject
@end
@implementation MySyncSessionObserver
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (![object isKindOfClass:RLMSyncSession.class]) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
if (![keyPath isEqualToString:@"connectionState"]) {
// Not interested in observing this keypath
return;
}
RLMSyncSession *syncSession = (RLMSyncSession *)object;
RLMSyncConnectionState connectionState = [syncSession connectionState];
switch (connectionState) {
case RLMSyncConnectionStateConnecting:
NSLog(@"Connecting...");
break;
case RLMSyncConnectionStateConnected:
NSLog(@"Connected");
break;
case RLMSyncConnectionStateDisconnected:
NSLog(@"Disconnected");
break;
}
}
@end

You can then attach an observer instance to the RLMSyncSession object. Be sure to remove the observer when finished.

// Observe connectionState for changes using KVO
MySyncSessionObserver *observer = [[MySyncSessionObserver alloc] init];
[syncSession addObserver:observer
forKeyPath:@"connectionState"
options:NSKeyValueObservingOptionInitial
context:nil];
// Later, when done...
[syncSession removeObserver:observer
forKeyPath:@"connectionState"
context:nil];
// Observe connectionState for changes using KVO
let observer = syncSession.observe(\.connectionState, options: [.initial]) { (syncSession, change) in
switch syncSession.connectionState {
case .connecting:
print("Connecting...")
case .connected:
print("Connected")
case .disconnected:
print("Disconnected")
default:
break
}
}
// Observe using Combine
let cancellable = syncSession.publisher(for: \.connectionState)
.sink { connectionState in
switch connectionState {
case .connecting:
print("Connecting...")
case .connected:
print("Connected")
case .disconnected:
print("Disconnected")
default:
break
}
}
const config: Realm.Configuration = {
schema: [DogSchema],
sync: {
user: app.currentUser!,
partitionValue: "MyPartitionValue",
},
};
const realm = await Realm.open(config);
const connectionState = realm.syncSession?.connectionState;

You can check the state of the Sync session itself to determine whether the sync session is active. The Sync connection state is distinct from the network connection state.

You can use the sync_session's public member function state() to check whether the sync session is active. This returns an enum whose value reflects possible Device Sync states.

To check the Sync state, you can read the Session instance's State property. Its value is a ConnectionState enum that reflects the current state of the Sync session's communication with the server.

You can get the state of the current Sync session state with Session.state. This returns a SessionState enum that contains the Sync session state, which is one of:

  • active

  • inactive

To check the current Sync state, call getState() on your SyncSession.

To check the current state of the Sync session, call the syncSession.state() method.

You can check the Sync session state through the SyncSession.State. This is a property of type State enum, whose possible values are:

  • INACTIVE

  • ACTIVE

  • PAUSED

  • DYING

  • WAITING_FOR_ACCESS_TOKEN

To check the current Sync state, call getState() on your SyncSession.

You can use the RLMSyncSession.state whose value reflects possible Device Sync states.

You can use the SyncSession.state property to check whether the Sync session is active. This property is a typealias for the RLMSyncSessionState enum whose value reflects possible Device Sync states.

To check the current state of the Sync session, call the syncSession.state() method.

syncSession->state();
// The documentation does not currently have this code example in C#.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Dart.
// Please refer to the other languages or related pages for example code.
// The documentation does not have this code example in Java.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in JavaScript.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Kotlin.
// Please refer to the other languages or related pages for example code.
// The documentation does not have this code example in Kotlin for the Java SDK.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Objective-C.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Swift.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in TypeScript.
// Please refer to the other languages or related pages for example code.

You can pause and resume the sync session on the database. Pausing a sync session only suspends that database's sync session. If you have more than one open database, and you have enabled multiple sync sessions, pausing one sync session does not affect the sync sessions for other databases.

To pause a sync session, call the sync session's pause() method.

syncSession->pause();

To resume a sync session, call the sync session's resume() method.

To pause synchronization for a specific session, you can call the Stop() method on the session.

When you then call the Start() method on the paused session, the Sync session resumes.

The following code block demonstrates calling the Stop() and Start() methods:

To pause syncing for a session, call Session.pause(). The database does not sync changes with Atlas while the session is paused.

To resume syncing a changes, call Session.resume().

To pause a currently active sync session, call stop() on your SyncSession:

SyncSession session = app.getSync().getSession(config);
session.stop();

To resume a currently paused sync session, call start() on your SyncSession:

To pause synchronization, use the syncSession.pause() method. To resume synchronization, use the syncSession.resume() method.

To pause syncing for a session, call syncSession.pause(). The database does not sync changes with Atlas while the session is paused.

To resume syncing changes, call syncSession.resume().

To pause a currently active sync session, call stop() on your SyncSession:

val session: SyncSession = app.sync.getSession(config)
session.stop()

To resume a currently paused sync session, call start() on your SyncSession:

You can pause a Sync session by calling RLMSyncSession.suspend() on a synced database instance.

Call RLMSyncSession.resume() to start syncing again.

You can pause a Sync session by calling SyncSession.suspend() on the SyncSession of a synced database instance.

You can resume a Sync session with SyncSession.resume().

To pause synchronization, use the syncSession.pause() method. To resume synchronization, use the syncSession.resume() method.

syncSession->resume();
var session = realm.SyncSession;
session.Stop();
//later...
session.Start();
// Pause the sync session
realm.syncSession.pause();
// Data that you add while the sync session is paused does not sync to Atlas.
// However, the data is still added to the realm locally.
realm.write(() {
realm.addAll<Car>([
Car(ObjectId(), "Volvo"),
Car(ObjectId(), "Genesis"),
Car(ObjectId(), "VW")
]);
});
// Resume sync session. Now, the data you wrote to the realm
// syncs to Atlas.
realm.syncSession.resume();
SyncSession syncSession = app.getSync().getSession(config);
syncSession.start();
const behaviorConfiguration = {
type: "openImmediately",
};
const config = {
schema: [DogSchema],
sync: {
user: app.currentUser,
partitionValue: "MyPartitionValue",
newRealmFileBehavior: behaviorConfiguration,
existingRealmFileBehavior: behaviorConfiguration,
},
};
const realm = await Realm.open(config);
const pauseSyncSession = () => {
realm.syncSession?.pause();
};
const resumeSyncSession = () => {
realm.syncSession?.resume();
};
// Pause the sync session
// Data that you write while session is paused does not sync to Atlas
realm.syncSession.pause()
// Add data locally
realm.write {
this.copyToRealm(Task().apply {
taskName = "Submit expense report"
assignee = "Kevin"
progressMinutes = 0
})
}
// Resume sync session
// Local changes now sync to Atlas
realm.syncSession.resume()
val syncSession: SyncSession = app.sync.getSession(config)
syncSession.start()
RLMRealm *syncedRealm = [RLMRealm realmWithConfiguration:configuration error:nil];
RLMSyncSession *syncSession = [syncedRealm syncSession];
// Suspend synchronization
[syncSession suspend];
// Later, resume synchronization
[syncSession resume];
let syncSession = syncedRealm.syncSession!
// Suspend synchronization
syncSession.suspend()
// Later, resume synchronization
syncSession.resume()
const behaviorConfiguration: Realm.OpenRealmBehaviorConfiguration = {
type: Realm.OpenRealmBehaviorType.OpenImmediately,
};
const config: Realm.Configuration = {
schema: [DogSchema],
sync: {
user: app.currentUser!,
partitionValue: "MyPartitionValue",
newRealmFileBehavior: behaviorConfiguration,
existingRealmFileBehavior: behaviorConfiguration,
},
};
const realm = await Realm.open(config);
const pauseSyncSession = () => {
realm.syncSession?.pause();
};
const resumeSyncSession = () => {
realm.syncSession?.resume();
};

For most applications, there is no need to manually pause and resume a sync session. However, there are a few circumstances under which you may want to pause or suspend a sync session:

  • You only want to sync after the user takes a specific action

  • You only want to sync during a certain time of the day

  • You don't want to attempt to sync when there is poor network connectivity

  • You want to force the SDK to re-evaluate the user's permissions after making a permissions-related change

In the case of poor network connectivity, continually trying to establish a network connection can drain the user's device battery.

The case of explicitly forcing a sync session to connect is most commonly related to being offline for some time. The sync client attempts to connect, and upon failure, goes into exponential backoff. After being offline for a long time, the client may not immediately reconnect. Pausing and resuming the sync session explicitly forces the connection.

When you do pause a sync session, keep these things in mind:

  • If the client may be offline longer than the client maximum offline time, the client will be unable to resume syncing and must perform a client reset.

  • Pausing a sync session pauses it in both directions. Changes that your app makes on the device do not sync with the backend, and changes to the data in the backend or on other devices do not sync to the device. There is no way to pause only uploads or pause only downloads.

  • Do not pause a sync session if you want a client to permanently stop syncing with the backend. To permanently stop syncing, copy the contents of the synced database into a non-synced database, and use the non-synced database in the client.

Do not pause sync to stop syncing for indefinite time periods or time ranges in months and years. The functionality is not designed or tested for these use cases. You could encounter a range of issues when using it this way.

You can wait for changes to upload or download. You might want to wait for changes to upload or download before you close a synced database, pause a Sync session, or change Sync subscriptions.

You can use the sync_session's wait_for_upload_completion() and wait_for_download_completion() methods to wait for changes to upload to or download from Atlas. Both of these methods can optionally take a callback to execute when upload or download is complete.

To wait for all changes to upload to Atlas from your synced database, use the member function wait_for_upload_completion().

syncSession->wait_for_upload_completion().get();

To wait for all changes from Atlas to download to your synced database, use the member function wait_for_download_completion(). Refresh the database after downloading any changes to be sure it reflects the most recent data.

To asynchronously wait for your changes to finish uploading, get the Sync session from the Realms.Sync.SyncSession property, and then call the session.WaitForUploadAsync() method.

To wait for changes to finish downloading, call the session.WaitForDownloadAsync() method.

To wait for the session to finish uploading all pending changes, call Session.waitForUpload().

To wait for the session to finish downloading all pending changes, call Session.waitForDownload().

Both of these sessions can take an optional CancellationToken to cancel the wait operation.

You can wait for changes to upload with SyncSession.uploadAllLocalChanges() or SyncSession.uploadAllLocalChanges(long timeout, TimeUnit unit). These methods block block execution until all known changes on the device have been uploaded to the server (or the specified timeout is hit).

You can wait for changes to download with SyncSession.downloadAllServerChanges() or SyncSession.downloadAllServerChanges(long timeout, TimeUnit unit). These methods block block execution until all known changes on the server have downloaded to the device (or the specified timeout is hit).

To asynchronously wait for all changes to upload to Atlas from your synced database, call uploadAllLocalChanges(). This method returns true when all changes have been uploaded.

To asynchronously wait for all changes on Atlas to download from the Device Sync server to your synced database, call downloadAllServerChanges(). This method returns true when all changes have been downloaded.

You can specify a request timeout on the App configuration. With a timeout specified, you can set cancelWaitsOnNonFatalErrors on your BaseSyncConfiguration. When true and the timeout interval arrives, any any outstanding work that is awaiting uploads and downloads cancels. When this setting is false, awaiting uploads and downloads does not cancel because the SDK treats these timeouts as non-fatal errors.

To asynchronously wait for all changes to upload to Atlas from your synced database, call uploadAllLocalChanges. This method returns true when all changes have been uploaded.

To asynchronously wait for all changes on Atlas to download from the Device Sync server to your synced database, call downloadAllServerChanges. This method returns true when all changes have been downloaded.

You can also include an optional timeout parameter to either method to determine the maximum amount of time before returning false. Note that the upload or download continues in the background even after returning false.

You can wait for changes to upload with SyncSession.uploadAllLocalChanges() or SyncSession.uploadAllLocalChanges(long timeout, TimeUnit unit). These methods block block execution until all known changes on the device have been uploaded to the server (or the specified timeout is hit).

You can wait for changes to download with SyncSession.downloadAllServerChanges() or SyncSession.downloadAllServerChanges(long timeout, TimeUnit unit). These methods block block execution until all known changes on the server have downloaded to the device (or the specified timeout is hit).

To wait for all changes to upload or download from your synced database, call:

These methods take a callback, which they dispatch onto the specified queue after the work item completes or the session expires.

To wait for all changes to upload or download from your synced database, call realm.syncSession?.wait(for: ).

This method takes a ProgressDirection argument to specify whether to track upload or download progress.

You can use these methods with Swift's async/await syntax, or with the callback syntax. The callback version, realm.syncSession?.wait(for:queue:block:), can take a queue to dispatch the callback onto, and a block to invoke when waiting is complete.

To asynchronously wait for all changes to upload to Atlas from your synced database, call uploadAllLocalChanges(). This method returns true when all changes have been uploaded.

realm.write(() => {
realm.create(Doggie, {
_id: new BSON.ObjectID(),
owner_id: app.currentUser!.id,
name: "Maui",
age: 3,
});
});
await realm.syncSession?.uploadAllLocalChanges();

To asynchronously wait for all changes on Atlas to download from the Device Sync server to your synced database, call downloadAllServerChanges(). This method returns true when all changes have been downloaded.

You can specify a request timeout on the App configuration. With a timeout specified, you can set cancelWaitsOnNonFatalErrors on your BaseSyncConfiguration. When true and the timeout interval arrives, any any outstanding work that is awaiting uploads and downloads cancels. When this setting is false, awaiting uploads and downloads does not cancel because the SDK treats these timeouts as non-fatal errors.

syncSession->wait_for_download_completion().get();
realm.refresh();
using Realms.Sync;
var realm = Realm.GetInstance(config);
await realm.SyncSession.WaitForDownloadAsync();
// The documentation does not currently have this code example in Dart.
// Please refer to the other languages or related pages for example code.
// The documentation does not have this code example in Java.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in JavaScript.
// Please refer to the other languages or related pages for example code.
// Wait to download all pending changes from Atlas
realm.syncSession.downloadAllServerChanges(1.minutes)
// Add data locally
realm.write {
this.copyToRealm(Task().apply {
taskName = "Review proposal"
assignee = "Emma"
progressMinutes = 0
})
}
// Wait for local changes to be uploaded to Atlas
realm.syncSession.uploadAllLocalChanges(1.minutes)
// The documentation does not have this code example in Kotlin for the Java SDK.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Objective-C.
// Please refer to the other languages or related pages for example code.

Async/Await

// Wait to download all pending changes from Atlas
try await realm.syncSession?.wait(for: .download)
// Add data locally
try realm.write {
realm.create(Task.self, value: [
"taskName": "Review proposal",
"assignee": "Emma",
"completed": false,
"progressMinutes": 0,
"dueDate": date
])
}
// Wait for local changes to be uploaded to Atlas
try await realm.syncSession?.wait(for: .upload)

Callback

// Wait to download all pending changes from Atlas
realm.syncSession?.wait(for: .download, block: { _ in
// You can provide a block to execute
// after waiting for download to complete
})
// Add data locally
do {
try realm.write {
realm.create(Task.self, value: [
"taskName": "Review proposal",
"assignee": "Emma",
"completed": false,
"progressMinutes": 0,
"dueDate": date
])
}
} catch {
print("There was an error writing to realm: \(error.localizedDescription)")
}
// Wait for local changes to be uploaded to Atlas
realm.syncSession?.wait(for: .upload, block: { _ in
// You can provide a block to execute after
// waiting for upload to complete
})
await realm.syncSession?.downloadAllServerChanges();

You can check the upload and download progress for a Sync session. You might want to check upload or download progress when you want to provide a progress estimate indicator in your app's user interface.

To monitor Sync progress, get the Sync session from the Realms.Sync.SyncSession property, then add a progress notification by calling the session.GetProgressObservable() method.

The session.GetProgressObservable method takes in the following two parameters:

  • A ProgressDirection parameter that can be set to Upload or Download.

  • A ProgressMode parameter that can be set to ReportIndefinitely for the notifications to continue until the callback is unregistered, or ForCurrentlyOutstandingWork for the notifications to continue until only the currently transferable bytes are synced.

When you Subscribe to the notifications, you receive a SyncProgress object that provides a percentage estimate of the current progress, expressed as a double between 0.0 and 1.0.

Once you no longer wish to receive notifications, unregister the token with token.Dispose().

In the following example, we subscribe to a progress observable on the session to listen for upload events. When this callback is triggered, it prints the upload progress as a percentage.

Changed in version 2.0.0: transferredBytes and transferrableBytes deprecated in favor of progressEstimate

To monitor Sync progress, call SyncSession.getProgressStream(). This method returns a Stream of SyncProgress objects that provide a progressEstimate for the current upload or download.

The provided progressEstimate is a double whose value ranges from 0.0 to 1.0. At 1.0, the progress stream is complete.

SyncSession.getProgressStream() takes two arguments:

  • A ProgressDirection enum that can be set to upload or download. Specifies whether the progress stream monitors upload or download progress.

  • A ProgressMode enum that can be set to one of the following:

    • reportIndefinitely: Sets notifications to continue until the callback is unregistered.

    • forCurrentlyOutstandingWork: Sets notifications to continue until the progressEstimate reaches 1.0.

To check the upload and download progress for a sync session, add a progress notification using the syncSession.addProgressNotification() method.

The syncSession.addProgressNotification() method takes in the following three parameters:

  • A direction parameter. Set to "upload" to register notifications for uploading data. Set to "download" to register notifications for downloading data.

  • A mode parameter. Set to "reportIndefinitely" for the notifications to continue until the callback is unregistered using syncSession.removeProgressNotification(). Set to "forCurrentlyOutstandingWork" for the notifications to continue until only the currently transferable bytes are synced.

  • A callback function parameter.

To monitor Sync upload and download progress, call SyncSession.progressAsFlow().

This method returns a Flow of Progress events. Progress provides an estimate, a double, that represents a transfer progress estimate that ranges from 0.0 to 1.0. It also provides an isTransferComplete bool.

syncSession.progressAsFlow() takes two arguments:

  • A Direction enum that can be set to UPLOAD or DOWNLOAD. This specifies that the progress stream tracks uploads or downloads.

  • A ProgressMode enum that can be set to either:

    • INDEFINITELY: Sets notifications to continue until the callback is unregistered.

    • CURRENT_CHANGES: Sets notifications to continue until only the currently transferable bytes are synced.

Changed in version 10.50.0: addProgressNotificationForDirection deprecated in favor of addSyncProgressNotificationForDirection

You can add a progress notification using the RLMSyncSession instance's addSyncProgressNotificationForDirection:mode:block: method.

This method returns a token that you should retain until you wish to stop observing upload or download progress. Note that if you keep the token in a local variable, observation will stop when the local variable goes out of scope.

Changed in version 10.50.0: transferredBytes and transferrableBytes deprecated in favor of progressEstimate

You can check upload and download progress by registering a token that provides a progressEstimate for a given upload or download direction and work scope. You can set a ProgressMode to determine the work scope: either observe indefinitely or unregister the block after the current work item has completed.

The progressEstimate value provided by the token is a double whose value ranges from 0.0 to 1.0. At 1.0, the upload or download is complete. You can use this progressEstimate to display a progress indicator or estimated data transfer percentage.

You can add a progress notification using the SyncSession instance's addProgressNotification(for:mode:block:) method.

This method returns a token that you should retain until you wish to stop observing upload or download progress. Note that if you keep the token in a local variable, observation will stop when the local variable goes out of scope.

To check the upload and download progress for a sync session, add a progress notification using the syncSession.addProgressNotification() method.

The syncSession.addProgressNotification() method takes in the following three parameters:

  • A direction parameter. Set to "upload" to register notifications for uploading data. Set to "download" to register notifications for downloading data.

  • A mode parameter. Set to "reportIndefinitely" for the notifications to continue until the callback is unregistered using syncSession.removeProgressNotification(). Set to "forCurrentlyOutstandingWork" for the notifications to continue until only the currently transferable bytes are synced.

  • A callback function parameter.

// The C++ SDK does not currently support this API.
var session = realm.SyncSession;
var token = session.GetProgressObservable(ProgressDirection.Upload,
ProgressMode.ReportIndefinitely)
.Subscribe(progress =>
{
Console.WriteLine($@"Current upload progress:
{progress.ProgressEstimate * 100}%");
});
token.Dispose();
final stream = realm.syncSession.getProgressStream(
ProgressDirection.upload, ProgressMode.forCurrentlyOutstandingWork);
late StreamSubscription streamListener;
streamListener = stream.listen((syncProgressEvent) {
final progressEstimate = syncProgressEvent.progressEstimate;
if (progressEstimate < 1.0) {
print('Upload progress: ${progressEstimate * 100}%');
}
}, onDone: () {
print("Upload complete");
}, onError: (error) {
print("An error occurred: $error");
streamListener.cancel();
});
// The Java SDK does not support this API.
// The documentation does not currently have this code example in JavaScript.
// Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Kotlin.
// Please refer to the other languages or related pages for example code.
// The Java SDK does not support this API.
RLMSyncSession *syncSession = [syncedRealm syncSession];
RLMProgressNotificationToken *token = [syncSession
addSyncProgressNotificationForDirection:RLMSyncProgressDirectionUpload
mode:RLMSyncProgressModeForCurrentlyOutstandingWork
block:^(RLMSyncProgress syncProgress) {
NSLog(@"Uploaded %fB", (double)syncProgress.progressEstimate);
}];
// Upload something
[syncedRealm transactionWithBlock:^{
[syncedRealm addObject:[[Task alloc] init]];
}];
let syncSession = realm.syncSession!
let token = syncSession.addProgressNotification(
for: .upload, mode: .forCurrentlyOutstandingWork) { (progress) in
let progressEstimate = progress.progressEstimate
let transferPercent = progressEstimate * 100
print("Uploaded (\(transferPercent)%)")
}
// The documentation does not currently have this code example in TypeScript.
// Please refer to the other languages or related pages for example code.

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

You can choose to manually trigger a reconnect attempt with with the reconnect method 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 the SDK's automatic reconnect detection.

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

The SDK has an internal default socket read timeout of 2 minutes. The SDK times out if a read operation does not receive any data within a 2-minute window. If you call the reconnect method within that window, the SDK does not attempt to reconnect.

You can choose to manually trigger a reconnect attempt with a sync session's reconnect() method.

You can choose to manually trigger a reconnect attempt with the App.reconnect() instead of waiting for the duration of the incremental backoff.

To attempt to manually reconnect all Sync sessions, call Realm.App.Sync.Session.reconnect().

In Kotlin SDK version 1.11.0 and later, you can choose to manually trigger a reconnect attempt with the App.Sync.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 (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.

New in version 10.44.0.

In Swift SDK version 10.44.0 and later, you can choose to manually trigger a reconnect attempt with RLMSyncSession.reconnect().

New in version 10.44.0.

In Swift SDK version 10.44.0 and later, you can choose to manually trigger a reconnect attempt with SyncSession.reconnect().

To attempt to manually reconnect all Sync sessions, call Realm.App.Sync.Session.reconnect().

syncSession->reconnect();
// The .NET SDK does not currently support this API.
app.reconnect();
// The Java SDK does not support this API.
// The documentation does not currently have this code example in JavaScript.
// Please refer to the other languages or related pages for example code.
app.sync.reconnect()
// The Java SDK does not support this API.
// The documentation does not currently have this code example in Objective-C.
// Please refer to the other languages or related pages for example code.
let syncSession = realm.syncSession!
// Work with the realm. When you need to force the sync session to reconnect...
syncSession.reconnect()
// The documentation does not currently have this code example in TypeScript.
// Please refer to the other languages or related pages for example code.

Back

Handle Sync Errors

Next

Stream Data to Atlas