https://kotlinlang.org logo
#coroutines
Title
# coroutines
v

vaskir

10/01/2018, 12:02 PM
Another example is a server process that spawns several children jobs and needs to supervise their execution, tracking their failures and restarting just those children jobs that had failed.
I cannot get my head around how to restart a children (say, an
actor
) from inside a
CoroutineExceptionHandler
😞 What I really need is just restarting strategy a-la Akka.
Copy code
fun CoroutineScope.worker(ctx: CoroutineContext) = actor<Int>(ctx) {
    for (msg in channel) {
        println("got $msg")
        if (msg == 2) throw Exception("it's $msg and we are failing")
    }
}

GlobalScope.launch {
    val supervisor = SupervisorJob()
    var actor: SendChannel<Int>?

    val handler = CoroutineExceptionHandler { _, _ ->
        {
            actor = worker(coroutineContext + supervisor + handler) // error: handler is not defined
        }
    }

    actor = worker(coroutineContext + supervisor + handler)

    for (msg in 1..5)
        actor?.send(msg)
}
e

elizarov

10/01/2018, 12:58 PM
It is not hard:
1. Don’t pass
ctx
into your
worker
function. It is bad style (now). Just define it as extension on
CoroutineScope
2. Restart the
worker
from handler like this:
Copy code
val handler = CoroutineExceptionHandler { context, error ->
        CoroutineScope(context).worker()
    }
Akka-style auto-restart is NOT a great idea for a language with mutable state. Indeed, it works perfectly in Erlang (that does not have any mutable state), but in Akka it just leads to tons of boilerplate and to just bad code in overall (you have to wrap every actor into a class, and you have to pass parameters to actors without type-safety, and you have to trust that it actually works)
v

vaskir

10/01/2018, 6:00 PM
Well, Akka Typed, which is close to release afaik, does not use mutable state, does not require actors to be classes and it's fully typed.
e

elizarov

10/01/2018, 7:01 PM
It is indeed much better, yet still too much boiler-plate for my taste.
We’ll be tacking design for more fully-featured actors after 1.0 release. There are a few ideas on where we can make it better. With (encapsulated) actors it does make sense to add some kind of auto-restart support, even though I’m not a fan — this kind of logic seems to be very project-specific. If you bake it into the library then you end up with too many configuration params. If it takes a few lines of code to implement restart, then it better be code
In kotlin you can literally write restart code with one line….
Copy code
val restart = CoroutineExceptionHandler { context, _ -> CoroutineScope(context).worker() }
We can add a “helper” to make into something like:
Copy code
val restart = CoroutineRestarter { worker() }
Does it really need further improvement?
v

vaskir

10/01/2018, 7:08 PM
I agree, too much ceremony. but I’m afraid if one were gonna implement features that it provides, he would write a lot of code, and the result would be way less reliable. I can pick kotlin now for an app i’m working on and will miss certain features soon (like supervising, clustering, persistence, out of the box monitoring and logging, a lot of integration adapters like amqp, mongo, kafka, etc, etc) Simple kotlin apps are indeed very clean and enjoy to write, but what I will do when I need it be production ready?
e

elizarov

10/01/2018, 7:09 PM
We don’t have any plans on writing a distributing programming framework. That is somebody else’s bread. We don’t plan to write any kind of framework for that matter. We are just providing core scaffolding and utilities.
Anyone can take Kotlin coroutines and go write a framework. I’m sure we’ll actually see multiple competing frameworks based on coroutines quite soon.
(I’m personally not a fan of frameworks at all… I’d never use something as magical as Akka for my own project)
v

vaskir

10/01/2018, 8:11 PM
I was there: I used a CML .NET port (channels, selective communication, IVar, MVar, streams etc.) for a number of applications and 1. it's very powerful 2. it's very hard to reason about the code structure, the actual paths data flies 3. it's not reliable, i.e. worker jobs can just die silently and it's error prone to check that all code is wrapped with try catch. As a result, apps just stopped on prod, which is the least thing you want to have. Now I use akka (streams mostly) instead, where I have explicit, reliable (i.e. supervised by default + restart strategies, etc.), asynchronous data transformation. That is all on .NET. Now I need to write an app on JVM and I'm not sure what to use: akka typed looks good and familiar, but the app cries for shared synchronous channels (work distribution), which is quite hard to achieve with actors. That's why I'm looking at Kotlin coroutines, which are simple, but not reliable.
j

jakiej

10/01/2018, 9:00 PM
just curious, what parts are not reliable?
3 Views