Skip to content

Commit

Permalink
fix: await reconciliation bug (#187)
Browse files Browse the repository at this point in the history
* fix: await reconcilliation bug

* refactor: replace delay with async-await

* fixup! refactor: replace delay with async-await
  • Loading branch information
nicklasl authored Nov 29, 2024
1 parent 95377ad commit a352533
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 5 deletions.
3 changes: 2 additions & 1 deletion Confidence/api/Confidence.api
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public final class com/spotify/confidence/Confidence : com/spotify/confidence/Co
public final fun activate ()V
public final fun apply (Ljava/lang/String;Ljava/lang/String;)V
public final fun asyncFetch ()V
public final fun awaitReconciliation (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun awaitReconciliation (JLkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun awaitReconciliation$default (Lcom/spotify/confidence/Confidence;JLkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
public final fun fetchAndActivate (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun flush ()V
public fun getContext ()Ljava/util/Map;
Expand Down
30 changes: 26 additions & 4 deletions Confidence/src/main/java/com/spotify/confidence/Confidence.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout
import kotlinx.coroutines.yield
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.encodeToJsonElement
Expand Down Expand Up @@ -60,11 +63,25 @@ class Confidence internal constructor(
}
}

suspend fun awaitReconciliation() {
if (currentFetchJob != null) {
suspend fun awaitReconciliation(timeoutMillis: Long = 5000) {
if (timeoutMillis <= 0) error("timeoutMillis need to be larger than 0")
debugLogger?.logMessage("reconciliation started")
yield() // will make sure that we respect other coroutine scopes triggered before this
withSafeTimeout(timeoutMillis) {
currentFetchJob?.join()
activate()
}
debugLogger?.logMessage("reconciliation completed")
}

private suspend fun withSafeTimeout(timeout: Long, block: suspend () -> Unit) {
try {
withTimeout(timeout) {
block()
}
} catch (e: TimeoutCancellationException) {
debugLogger?.logMessage("timed out after $timeout")
}
}

/**
Expand Down Expand Up @@ -238,7 +255,9 @@ class Confidence internal constructor(
* made available in the app session.
*/
fun asyncFetch() {
currentFetchJob?.cancel()
currentFetchJob?.cancel().also {
currentFetchJob = null
}
currentFetchJob = fetch()
}

Expand All @@ -249,7 +268,9 @@ class Confidence internal constructor(
* Fetching is best-effort, so no error is propagated. Errors can still be thrown if something goes wrong access data on disk.
*/
suspend fun fetchAndActivate() = kotlinx.coroutines.withContext(dispatcher) {
currentFetchJob?.cancel()
currentFetchJob?.cancel().also {
currentFetchJob = null
}
currentFetchJob = fetch()
currentFetchJob?.join()
activate()
Expand Down Expand Up @@ -337,6 +358,7 @@ object ConfidenceFactory {
clientSecret = clientSecret,
region = region,
httpClient = OkHttpClient.Builder()
.connectTimeout(timeoutMillis, TimeUnit.MILLISECONDS)
.callTimeout(timeoutMillis, TimeUnit.MILLISECONDS)
.build(),
dispatcher = dispatcher,
Expand Down

0 comments on commit a352533

Please sign in to comment.