You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug MutableStore doesn't emit any values If you have a Store and you cancel flows then start new ones using store.stream.
I believe this is due to a deadlock that happens where one the locks remains locked when a cancellation exception is propagated. I've wrote a simple test to reproduce it.
We have an iOS app and use Kotlin multiplatform and that's where we noticed the issue. One of our flows cancel and relaunches a MutableStore streams and we noticed the whole app just doesn't get any data from the store.
This is only happening on a MutableStore. If you switch the provided test into a non-mutable store the test consistently passes.
// This is test class was chosen just of convenience. It already exist in the "Store" repo.
class StoreWithInMemoryCacheTests {
....
@Test
fun storeDeadlock() =
testScope.runTest {
repeat(1000) {
val store =
StoreBuilder
.from(
fetcher = Fetcher.of { key: Int -> "fetcher_${key}" },
sourceOfTruth = SourceOfTruth.Companion.of(
reader = { key ->
flow<String> {
emit("source_of_truth_${key}")
}
},
writer = { key: Int, local: String ->
}
)
)
.disableCache()
.toMutableStoreBuilder(
converter = object : Converter<String, String, String> {
override fun fromNetworkToLocal(network: String): String {
return network
}
override fun fromOutputToLocal(output: String): String {
return output
}
},
)
.build(
updater = object : Updater<Int, String, Unit> {
var callCount = -1
override suspend fun post(key: Int, value: String): UpdaterResult {
callCount += 1
if (callCount % 2 == 0) {
throw IllegalArgumentException(key.toString() + "value:$value")
} else {
return UpdaterResult.Success.Untyped("")
}
}
override val onCompletion: OnUpdaterCompletion<Unit>?
get() = null
}
)
val jobs = mutableListOf<Job>()
jobs.add(
store.stream<Nothing>(StoreReadRequest.cached(1, refresh = true))
.mapNotNull { it.dataOrNull() }
.launchIn(CoroutineScope(Dispatchers.Default))
)
val job1 = store.stream<Nothing>(StoreReadRequest.cached(0, refresh = true))
.mapNotNull { it.dataOrNull() }
.launchIn(CoroutineScope(Dispatchers.Default))
jobs.add(
store.stream<Nothing>(StoreReadRequest.cached(2, refresh = true))
.mapNotNull { it.dataOrNull() }
.launchIn(CoroutineScope(Dispatchers.Default)))
jobs.add(
store.stream<Nothing>(StoreReadRequest.cached(3, refresh = true))
.mapNotNull { it.dataOrNull() }
.launchIn(CoroutineScope(Dispatchers.Default)))
job1.cancel()
assertEquals(
expected = "source_of_truth_0",
actual = store.stream<Nothing>(StoreReadRequest.cached(0, refresh = true))
.mapNotNull { it.dataOrNull() }.first()
)
jobs.forEach {
it.cancel()
assertEquals(
expected = "source_of_truth_0",
actual = store.stream<Nothing>(StoreReadRequest.cached(0, refresh = true))
.mapNotNull { it.dataOrNull() }.first()
)
}
}
}
To Reproduce
Steps to reproduce the behavior:
Go to StoreWithInMemoryCacheTests
Add the provided test
Run it with :store:cleanIosSimulatorArm64Test :store:iosSimulatorArm64Test --tests "org.mobilenativefoundation.store.store5.StoreWithInMemoryCacheTests.storeDeadlock" or :store:testDebugUnitTest --tests "org.mobilenativefoundation.store.store5.StoreWithInMemoryCacheTests.storeDeadlock"
See test sometimes timing out and sometimes succeeding (with low repeat count).
Expected behavior
Test always succeeds
Screenshots
If applicable, add screenshots to help explain your problem.
Smartphone (please complete the following information):
OS: iOS and Android
Store Version: 5.0.0-beta02 and 5.0.0-alpha04
The text was updated successfully, but these errors were encountered:
Describe the bug
MutableStore
doesn't emit any values If you have aStore
and you cancel flows then start new ones usingstore.stream
.I believe this is due to a deadlock that happens where one the locks remains locked when a cancellation exception is propagated. I've wrote a simple test to reproduce it.
We have an iOS app and use Kotlin multiplatform and that's where we noticed the issue. One of our flows cancel and relaunches a
MutableStore
streams and we noticed the whole app just doesn't get any data from the store.This is only happening on a MutableStore. If you switch the provided test into a non-mutable store the test consistently passes.
To Reproduce
Steps to reproduce the behavior:
StoreWithInMemoryCacheTests
:store:cleanIosSimulatorArm64Test :store:iosSimulatorArm64Test --tests "org.mobilenativefoundation.store.store5.StoreWithInMemoryCacheTests.storeDeadlock"
or:store:testDebugUnitTest --tests "org.mobilenativefoundation.store.store5.StoreWithInMemoryCacheTests.storeDeadlock"
Expected behavior
Test always succeeds
Screenshots
If applicable, add screenshots to help explain your problem.
Smartphone (please complete the following information):
The text was updated successfully, but these errors were encountered: