All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hildan.hashcode.utils.runner.ParallelRunner.kt Maven / Gradle / Ivy

package org.hildan.hashcode.utils.runner

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import java.util.Collections
import java.util.concurrent.CopyOnWriteArrayList

/**
 * Runs the given function on each of the given input, each in its own coroutine.
 *
 * Note: Depending on your choice of [UncaughtExceptionsLogger], you may need to provide an SLF4J implementation
 * on your classpath to be able to see error logs.
 *
 * @param I the type of input that the block handles
 *
 * @param exceptionsLogger defines what to do with uncaught exceptions thrown by [block]
 * @param block the block to run on the inputs given to [run]
 */
suspend fun  runInParallel(
    vararg inputs: I,
    exceptionsLogger: UncaughtExceptionsLogger = UncaughtExceptionsLogger.STDERR,
    remindExceptionsAtTheEnd: Boolean = true,
    block: suspend (I) -> Unit
) {
    val exceptions = Collections.synchronizedList(mutableListOf>())
    coroutineScope {
        inputs.forEach {
            launch(Dispatchers.Default) {
                try {
                    block(it)
                } catch (e: Exception) {
                    exceptionsLogger.log("Uncaught exception thrown during task execution:", e)
                    exceptions.add(ExecException(it, e))
                }
            }
        }
    }
    if (exceptions.isNotEmpty() && remindExceptionsAtTheEnd) {
        remindExceptions(exceptions, exceptionsLogger)
    }
}

private fun  remindExceptions(exceptions: List>, exceptionsLogger: UncaughtExceptionsLogger) {
    exceptionsLogger.log("${exceptions.size} tasks terminated abruptly by throwing exceptions")
    exceptions.forEach {
        val message = "Reminder: this exception was thrown while running on input ${it.input}: ${it.exception.message}"
        exceptionsLogger.log(message, it.exception)
    }
}

private data class ExecException(val input: I, val exception: Exception)