Retain observed settings through read failures and retry without default resets

This commit is contained in:
evgeny committed 2026-10-29 13:35:19 +01:00
1 parent e8aeaaf365
commit 61bdf4a6df
2 files changed
+24

No files matched your search

@@ -7,8 +7,11 @@ import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.retryWhen
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
@@ -37,4 +40,13 @@ class SettingsOperations(private val scope: CoroutineScope = CoroutineScope(Supe
}
fun dismissFailure() { _failed.value = false }
suspend fun awaitIdle() { mutex.withLock { } }
/** Ошибка чтения не публикует defaults поверх последнего значения и не завершает подписку UI. */
fun <T> observe(name: String, values: Flow<T>): Flow<T> = values.retryWhen { error, attempt ->
if (error is CancellationException || error !is Exception) false else {
reportFailure(name, error)
delay((250L shl attempt.toInt().coerceIn(0, 7)).coerceAtMost(30_000))
true
}
}
}
@@ -6,6 +6,9 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.flow.toList
import org.junit.Assert.*
import org.junit.Test
@@ -39,4 +42,13 @@ class SettingsOperationsTest {
val waiter = launch { owner.awaitIdle() }; waiter.cancel()
gate.complete(Unit); change.await(); assertTrue(saved); assertFalse(change.isCancelled)
}
@Test fun failedPreferenceObservationPreservesTheLastValueAndCanRecover() = runTest {
val owner = SettingsOperations(this) { _, _ -> }; var attempts = 0
val values = flow {
if (++attempts == 1) { emit(42); throw java.io.IOException("read failed") }
emit(43)
}
assertEquals(listOf(42, 43), owner.observe("preferences", values).take(2).toList())
assertTrue(owner.failed.value); assertEquals(2, attempts)
}
}