Skip to content

Coroutines launched in actor are not getting cancelled when we close the actor channel #836

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
DilbagSandhu opened this issue Nov 14, 2018 · 8 comments
Labels

Comments

@DilbagSandhu
Copy link

as the title says. if I launch a coroutine in actor and when I close the channel of the actor, coroutine not getting cancelled.
if coroutine inherit the actorscope should not they be cancelled if the channel associated with it, sends the close signal.

@Bluexin
Copy link

Bluexin commented Nov 14, 2018

Closing the channel just breaks the for (msg in channel) loop.
So if you want to cancel children when channel is closed, do it after that (by cancelling the current actor).

Did you try closing the channel with an exception?

@DilbagSandhu
Copy link
Author

so there is no direct way to signal the actor to close the channel and cancel all associated coroutines?

@Bluexin
Copy link

Bluexin commented Nov 14, 2018

Maybe if you close the channel with an exception, I haven't tried that but it should propagate the exception (cancelling children coroutines).

@elizarov
Copy link
Contributor

elizarov commented Nov 14, 2018

UPDATE: Please unsee this comment. Confirm. This is indeed a problem. Conceptually, closing an actor should cancel its coroutine which should cancel all its children, but it is not happening as the following example demonstrates:

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*

fun CoroutineScope.testActor() = actor<String> {
    launch {
        delay(10000) // long-running child
    }
    for (msg in channel) {
        println(msg)
    }
}

fun main() = runBlocking<Unit> {
    val actor = testActor()
    actor.send("Foo")
    actor.close()
}

It terminates in 10sec, but is expected to terminate immediately.

@Bluexin
Copy link

Bluexin commented Nov 14, 2018

Would be a good thing to take into account for #485 (I didn't try to make much sense of that yet, I'm still learning about the actors concept itself)

@elizarov
Copy link
Contributor

Here is the actual explanation:

Closing the actor's channel (invoking channel.close) literally means the following: I'm no longer planning to send any more message to this actor, please complete (normally) what you were doing and terminate. Closing actor's channel is not cancelling. Actor can still have background children jobs that should continue to work until their normal termination. If you need to cancel the actor (force it to abort without finishing processing the messages) you should cancel its scope. For example if you replace actor.cancel() with throw IOException("We had failed -- abort everything") in my previous example, then actor is cancelled.

@DilbagSandhu
Copy link
Author

but what if we want to signal actor ("your work no longer needed(not failed) -- abort everything").
even if I send CancellationException with a close method like actor.close(CancellationException()) it reaches there in the next iteration of channel loop. the actor still continues to do work which I no longer needed.

@qwwdfsad
Copy link
Collaborator

The example of how to do it is written in the KDoc to actor:

If the actor needs to be aborted without processing all the messages that were already sent to it, then it shall be created with a parent job:

val job = Job()
val c = actor(context = job) {  ... }
 ...
// abort the actor
job.cancel()

But this is a bit verbose and error-prone, in #87 we will address this issue properly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants