If you look at it from afar, coroutines are a way ...
# coroutines
c
If you look at it from afar, coroutines are a way to abstract on top of state machines. And well, there is another type of state machines that we often use, that would benefit from such an abstraction. Business processes are often specified in an algorithmic fashion:
Copy code
The user A does the action a.
The user B is then asked to accept or refuse.
If the user B accepted, the user A is asked to confirm or cancel their approval.
Then, the entity on which the actions were made is marked as done.
However, we are often working on distributed applications (client-server, replicated servers...). We often end up using event-based architectures, which leads to this kind of code:
Copy code
fun onActionA(...) {
    require(currentUser == A)
    // the process here
    entity.state = Created(by = currentUser)
}

fun onAcceptOrRefuse(...) {
    check(currentUser == B)
    check(entity.state is Created)
    // The process here
    entity.state = Accepted(by = currentUser)
}

...
This works, but it's particularly verbose and it obscures the algorithm. It makes everything harder to maintain and harder to debug: where do events come from? Instead, I'd like to re-use the
suspend
keyword to generate the state machine implicitly:
Copy code
suspend fun process() {
    val initial = await(actionA from A)
    service.create(...)
    
    val acceptation = await(AcceptOrRefuse from B)
    if (acceptation.accept) {
        val confirmation = await(ConfirmOrCancel from A)
        if (confirmation.confirmed) {
            service.markConfirmed(...)
        } else {
            service.markCancelled(...)
        }
    } else {
        service.markRefused(...)
    }
    
    service.markDone(...)
}
This would make it much easier to understand what the process is. And, it's not initially that complex to implement! The problem is: how do you resume this system? If the server dies, and thus the coroutine disappears, how to re-create the coroutine at the same point it was previously, so the process isn't interrupted?
cc @Youssef Shoaib [MOD] I believe you were working on multi-shot coroutines, and this problem is somewhat similar?
a
iirc, being able to stop/resume a process that uses coroutines depends on being able to serialize them, which was raised and experimented with, but wasn't easy to finalize https://github.com/Kotlin/kotlinx.coroutines/issues/76
You might be interested to see how KGP uses something similar to what you're suggesting. It uses suspension (without kotlinx.coroutines) to coordinate configuration, which can be really difficult in the Gradle world https://github.com/JetBrains/kotlin/blob/a8e637205c43aef3284907152584eb427490bcc1/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginLifecycle.kt#L236-L235
c
Thanks, I'll look into it