groostav
11/16/2018, 7:12 AM//producer function following conventional (?) coroutine parent-child-ing as per Romans Coroutines part II at kotlinconf 2018
fun CoroutineScope.longRunningProducer(): RecieveChannel<Info> { ... }
//then a user
fun someUser(){
println("started!")
runBlocking {
val selfScope: CoroutineScope = this@runBlocking
val producer: RecieveChannel<Info> = selfScope.longRunningProducer()
for(item in producer){
if(businessLogic(item)) {
//bail!
break;
}
else //...
}
println("almost done!")
}
println("done!")
}
if longRunningProducer
started!
almost done!
because the nestedEventLoop
wont close until its children are done.
What I'd like to have happen is for an abandoned longRunningProducer
coroutine to simply get garbage collected, but I guess that means I gotta be careful with weakReferences
and such, yeah?gildor
11/16/2018, 7:38 AMgroostav
11/17/2018, 7:45 AMyield
another element. I could enforce some kind of timeout policy, but in my case its not unreasonable to have a producer go for hours without producing anything. Think of a cron-job or scheduled task kinda thing.runBlocking {
launch {
delay(999_999_999)
}
}
println("done!")
means done
will never get printed because by attaching a child-coroutine that is effectively abandoned to a parent scope, runBlocking
wont exit until the child job is finished. I dont want that. But I do want the fact that if you cancel the parent, the child is also cancelledlaunchDaemon
to get what I want...
@Test fun `one can create daemon coroutines with onjoin`() = runBlocking<Unit> {
runBlocking {
launchDaemon {
println("I'm a daemon!")
doLongRunningPossiblyAbandonedProcess()
println("daemon is done!")
}
launch {
println("I'm a prime job!")
delay(10)
println("prime job is done!")
}
println("last line in outer job")
}
println("outer job returned")
}
private suspend fun CoroutineScope.launchDaemon(job: suspend CoroutineScope.() -> Unit){
val runningJob = GlobalScope.launch(block = job)
val parentJob = this.coroutineContext[Job]!!
GlobalScope.launch {
val cancel = select<Boolean>{
runningJob.onJoin { false }
parentJob.onJoin { true }
}
if(cancel) runningJob.cancel()
}
}
gildor
11/21/2018, 8:15 AMthat also begs the question: how does one listen for cancellation...
Job.invokeOnCompletion()
meansYes, as I said, what is your target strategy in this case? I suggested to use withTimeout, because if some process is abandoned it means something went wrong, or if it’s fine you need some strategy how detach from it, by timeout or by some event that clean ups coroutines, for both cases it can be easily achieved, but not clear what is your casewill never get printeddone
Of course, but what do you want? Also probably runBlocking is probably bad choice, because not clear here, is it just an example or you really want to use itwont exit until the child job is finished.runBlocking
I do want the fact that if you cancel the parent, the child is also cancelledThis is how Job and nested coroutines work