William Reed
06/25/2021, 5:58 PMsuspend fun
and wait for the result. however i am calling multiple `suspend fun`s from throughout my code base. I’m trying to think of a way to group these together and allow them to queue since each of the call sites uses a separate context/scope. another requirement is that if a particular command completes, it can cancel all remaining commands that are queued up. my first attempt at it in the thread -->William Reed
06/25/2021, 5:58 PMimport kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
fun main() = runBlocking {
val lock = CloseableMutex()
// from class A in scope A
queuedLaunch(lock) {
// create a command and poll on it ...
println("hello")
delay(2_000)
}
// from class B in scope B
queuedLaunch(lock, terminateQueueAfterwards = true) {
// create a command and poll on it ...
println("hello 2")
delay(1_000)
}
// from class C in scope C
queuedLaunch(lock) {
// create a command and poll on it ...
println("hello 3")
delay(3_000)
}
}
fun CoroutineScope.queuedLaunch(
mutex: CloseableMutex,
context: CoroutineContext = EmptyCoroutineContext,
terminateQueueAfterwards: Boolean = false,
block: suspend CoroutineScope.() -> Unit,
) {
launch(context) {
// wait my turn
mutex.withCancellableLock {
// then execute
block()
if (terminateQueueAfterwards) {
mutex.closed = true
}
}
}
}
class CloseableMutex: Mutex by Mutex() {
var closed = false
suspend inline fun <T> withCancellableLock(owner: Any? = null, action: () -> T): T =
withLock(owner) {
if (closed) throw CancellationException()
else action()
}
}
William Reed
06/25/2021, 5:58 PMhello
hello 2
William Reed
06/25/2021, 5:59 PMqueuedLaunch
extension function seems a bit against the grain of normal coroutines usage. I’m just struggling to think of some other ways to achieve this - hoping for some suggestions 🙂CLOVIS
06/26/2021, 9:01 AM