Search code examples
kotlin-coroutinescoroutine

Why intermediate coroutine hangs up top level coroutine?


Where is task to process big list of items in sequential-parallel way: split big list to chunks, process chunks one after another, process items from each chunk in parallel. Implementing this task, I encounter a problem and reduce that task to reproduce it in simplest way.

val rootScope = CoroutineScope(Dispatchers.IO)

val list: List<Int> = listOf(1,2,3,4,5)

rootScope.launch {
    val rootLocalScope = this
    log("-----> rootScope (start)")

    launch {
        val mediumLocalScope = this

        list.map {  i ->
            // 
            // Replace rootLocalScope to mediumLocalScope in SupervisorJob() and hangs up work...
            //
            launch (SupervisorJob(rootLocalScope.coroutineContext.job)) {
                log("Downloading file-$i")
                delay(1000)
            }
        }.joinAll()
        
    }.join()

    log("-----> rootScope (finish)")
}

Remark: all .join() are required, there is no right sequence of work without it.

Output is:

With SupervisorJob(rootLocalScope.coroutineContext.job):

========= work() ========
-----> rootScope (start)
Downloading file-1
Downloading file-2
Downloading file-3
Downloading file-4
Downloading file-5
-----> rootScope (finish)

With SupervisorJob(mediumLocalScope.coroutineContext.job):

========= work() ========
-----> rootScope (start)
Downloading file-1
Downloading file-2
Downloading file-3
Downloading file-4
Downloading file-5
*I.e. top level coroutine not reached its finish...*

So, the question: why SupervisorJob(mediumLocalScope.coroutineContext.job) not works?


Solution

  • I found on StackOverflow similar theme. Shortly: you shoud manually call .complete() on intermediate job (SupervisorJob in discussed case, but simple Job behaves the same) after .joinAll() child jobs.