Lawrence
06/10/2022, 6:35 PM// The api I am working with is blocking and throws an error if not connected
suspend fun determineType(): Type? {
var type: Type? = null
withTimeoutOrNull(15.seconds) {
while (type == null) {
select<Unit> {
async {
runInterruptible(<http://Dispatchers.IO|Dispatchers.IO>) {
kotlin.runCatching { apiA.typeA }.getOrNull()
}
}.onAwait {
if (it != null) {
make = it
}
}
async {
runInterruptible(<http://Dispatchers.IO|Dispatchers.IO>) {
kotlin.runCatching { apiB.typeB }.getOrNull()
}
}.onAwait {
if (it != null) {
type = it
}
}
}
}
}
return type
}
mkrussel
06/10/2022, 6:42 PMasync
before the select and the while, and then just do the onAwaits
inside the select.
This is for flows, but it should give you a pattern to follow.
https://proandroiddev.com/implement-race-amb-operator-with-kotlin-coroutines-flow-a59f17997b67phldavies
06/10/2022, 7:22 PMLawrence
06/10/2022, 8:18 PM@OptIn(ExperimentalCoroutinesApi::class)
suspend fun determine() = coroutineScope {
var type: Type? = null
val jobs =
listOf(apiA, apiB).map {
async(<http://Dispatchers.IO|Dispatchers.IO>) {
runInterruptible {
kotlin.runCatching { it.callApi() }.getOrNull()
}
}
}
whileSelect {
onTimeout(15.seconds) { false }
jobs.forEach { deferred ->
deferred.onAwait {
it?.let {
type = it
false
}
?: true
}
}
}
.also { coroutineContext.cancelChildren() }
type
}
}
ephemient
06/11/2022, 7:06 AMsuspend fun Iterable<() -> Unit>.indexOfSuccess() = mapIndexed { i, block ->
flow {
runInterruptible {
runCatching(block)
}.onSuccess { emit(i) }
}
}.merge().firstOrNull()
withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
withTimeoutOrNull(15_000) {
listOf(apiA::callApi, apiB::callApi).indexOfSuccess()
}
}
rcgroot
06/14/2022, 1:09 PMit.callApi()
part in my case was not-interruptible.
I think I had to resort to something (horrible) as running the callApi()
in a different scope, because cancel will detach a scope immediately.