Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for automatic resetting incremental backoff when network status changes #1491

Merged
merged 20 commits into from
Sep 1, 2023

Conversation

cmelchior
Copy link
Contributor

@cmelchior cmelchior commented Aug 25, 2023

Closes #1479

This PR exposes a number of methods relevant to controlling the network connection and session lifecycle. It does this through a new Sync class that is exposed through App.Sync, similar to Realm Java.

Before this PR, reconnecting was handled purely by Core, which used incremental backoff. In the worst case, this meant that the Sync connection was not established until 5 minutes after the device was online again (the limit in Core)

With this PR a new Sync.reconnect() method is added that makes it possible to trigger a manual reconnect if users have better insight into when the network condition changed, e.g. through the ConnectivityManager on Android.

It also adds a best-effort implementation for doing this automatically: https://github.com/realm/realm-kotlin/pull/1491/files#diff-835b655f827ffc568b4fd6c04722b17faf9ec56fe73289379bfdad6723d5a00bR79.

Note, that automatic reconnect detection is only available on Android, iOS, and macOS. JVM has no APIs we can hook into.

TODO

  • Add tests
  • Figure out how this works on Darwin. Answer: Core is responsible for setting this up on Darwin platforms, thus no changes are needed here and automatic reconnect worked, also before this PR.

@cmelchior cmelchior marked this pull request as ready for review August 30, 2023 17:02
@cmelchior
Copy link
Contributor Author

Finally ready for review. For some reason, this PR exposed some race conditions in our test setup caused by us not shutting down all test apps correctly. So a long list of changes here are just associated with fixing this (Basically all apps now have a unique ID that will make it easier to find and fix threading test errors in the future)

import io.realm.kotlin.internal.interop.SynchronizableObject

// Register a system specific network listener (if supported)
internal expect fun registerSystemNetworkObserver()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the idea, but since all implementations are no-ops, does it then make sense to have it at all 🤔

fun isConnected(cm: ConnectivityManager?): Boolean {
return cm?.let {
val networkInfo: NetworkInfo? = cm.activeNetworkInfo
networkInfo != null && networkInfo.isConnectedOrConnecting || isEmulator()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are emulator always connected?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea 😅 ... I pulled this code from somewhere else and has never really questioned it 🙈

@@ -49,7 +49,7 @@ class ApiKeyAuthTests {

@BeforeTest
fun setup() {
app = TestApp(appName = TEST_APP_PARTITION)
app = TestApp(this::class.simpleName, appName = TEST_APP_PARTITION)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess not for this PR, but would be awfully nice if we could just inject the test name from a rule or something like that. This seems like a really annoying thing to have to always write ... but I guess less annoying than trying to debug without it 😅

Copy link
Contributor

@rorbech rorbech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM and great clean up. Would be interesting to see if this clears up the GHA test clean up issues on Windows 🧐

@@ -32,7 +32,7 @@ public data class RealmInstantImpl(override val seconds: Long, override val nano
}
}

internal fun RealmInstant.toDuration(): Duration {
public fun RealmInstant.toDuration(): Duration {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for this PR, but we could consider to make this a public-public extension.

}
if (connectionAvailable && (lastOnlineStateReportedMs == null || nowMs - lastOnlineStateReportedMs!! > reconnectThresholdMs)
val now: Duration = RealmInstant.now().toDuration()
if (connectionAvailable && (lastOnlineStateReported == null || now.minus(lastOnlineStateReported!!) > reconnectThreshold)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 ... I guess you could make it more Kotlin idiomatic with something like

if (connectionAvailable && (lastOnlineStateReported?.let { now - it > reconnectThreshold } != false))

but don't mind keeping it as is.

@cmelchior cmelchior merged commit 9138b66 into main Sep 1, 2023
1 check passed
@cmelchior cmelchior deleted the cm/automatic-reconnect branch September 1, 2023 09:21
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 14, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add SyncSession.reconnect
2 participants